Load libraries and data
root.dir <- "~/OneDrive/projects/"
project.dir <- paste0(root.dir,"PDX/")
source(paste0(root.dir,"R.utils/RNASEQ.utils.R"))
Attaching package: 'limma'
The following object is masked from 'package:BiocGenerics':
plotMA
Attaching package: 'scales'
The following object is masked from 'package:ggbio':
rescale
source(paste0(project.dir,"src/load.PDX.R"))
rnaseq <- get.PDX()
|--------------------------------------------------|
|==================================================|
meta <- load.meta()
meta <- subset.meta(meta,meta[,project=="drug.selu"])
rnaseq <- subset.PDX(rnaseq, rnaseq$meta[,Sample.name] %in% meta[,Sample.name])
QC
read.depth.plots(rnaseq$meta)


We should remove the runs that contain very few reads before we merge otherwise they could bias the subsequent analysis.
rnaseq <- subset.PDX(rnaseq, rnaseq$meta[,human.library.size>1E6])
Repeat QC plots:
read.depth.plots(rnaseq$meta)


rnaseq <- merge.PDX(rnaseq)
rnaseq$meta <- merge(rnaseq$meta,meta,sort=F)
unique(rnaseq$meta[,.(merged.lanes,as.numeric(as.factor(merged.lanes)))])
merged.lanes
1: SLX-14082:HMW3VBBXX:s_4;SLX-14082:HMW3VBBXX:s_5;SLX-14082:HMW3VBBXX:s_6;SLX-14082:HMW3WBBXX:s_2;SLX-14082:HMW3WBBXX:s_3;SLX-14082:HMW3WBBXX:s_4;SLX-14082:HMW3WBBXX:s_5;SLX-14082:HMW3WBBXX:s_6;SLX-14082:HMW5MBBXX:s_1
2: SLX-14085:HL7TLBBXX:s_4;SLX-14085:HLCCLBBXX:s_5;SLX-14085:HLGY5BBXX:s_7
3: SLX-14086:HK2C7BBXX:s_6;SLX-14086:HK2C7BBXX:s_7;SLX-14086:HK2C7BBXX:s_8
4: SLX-14906:HLKN7BBXX:s_5
V2
1: 1
2: 2
3: 3
4: 4
rnaseq$meta[,merged.lanes:=as.numeric(as.factor(merged.lanes))]
What samples remain after all that QC:
table(unique(rnaseq$meta[,.(PDX,Treatment,Mouse)])[,.(PDX,Treatment)])
Treatment
PDX Selumetinib Unknown Vehicle
HCI009 4 0 6
STG139 5 0 5
STG316 3 0 2
VHIO098 5 1 4
VHIO098OR 7 0 7
Note that the VHIO098 samples contain duplicates (as noted by mice numbers).
rnaseq$meta[,.N,.(Mouse,PDX,Treatment)][N>1]
Mouse PDX Treatment N
1: 29378 VHIO098 Selumetinib 2
2: 29382 VHIO098 Selumetinib 2
3: 29358 VHIO098 Selumetinib 2
4: 29383 VHIO098 Selumetinib 2
5: 29381 VHIO098 Vehicle 2
6: 29379 VHIO098 Vehicle 2
Let’s use these duplicates to see if the assignment of human and mouse reads suffered by reducing to SE50 sequencing Note: merged.lane==1 –> SLX-14082; which is SE50)
x <- rnaseq$meta[Mouse %in% rnaseq$meta[,.N,.(Mouse,PDX,Treatment)][N>1,Mouse]][order(Mouse),.(Sample.name,Mouse,merged.lanes,mouse.library.size/(mouse.library.size+human.library.size))]
ggplot(x) + aes(x=Mouse,y=V4,colour=factor(merged.lanes)) + geom_point(size=5) + theme_wsj() + coord_flip()

There does not appear to be a signifgant change in the mouse fraction due to sequencing. However, lane 4 that which contains all the duplicates (news!), has consistantly lower amounts of mouse. I do not know why all the duplicates are found within SLX-14906. Are all of SLX-14906 duplicates?
rnaseq$meta[Mouse %in% rnaseq$meta[merged.lanes==4,Mouse]][order(Mouse),.(Sample.name,merged.lanes,Treatment,Processing.batch)]
Sample.name merged.lanes Treatment Processing.batch
1: VHIO098-T1-x03-16.029358-T1 1 Selumetinib NA
2: VHIO098-T1-x03-16.029358-C1-Sel 4 Selumetinib 2
3: VHIO09-T1-x03-16.029378-T1 1 Selumetinib NA
4: VHIO098-T1-x03-16.029378-C1-Sel 4 Selumetinib 2
5: VHIO098-X3_29379_Vehicle_R1 3 Vehicle 1
6: VHIO098-T1-x03-16.029379-C1-Veh 4 Vehicle 2
7: VHIO098-X3_29381_Vehicle_R1 2 Vehicle 1
8: VHIO098-T1-x03-16.029381-C1-Veh 4 Vehicle 2
9: VHIO098-T1-x03-16.029382-T1 1 Selumetinib NA
10: VHIO098-T1-x03-16.029382-C1-Sel 4 Selumetinib 2
11: VHIO098-X3_29383_Selu_R1 2 Selumetinib 1
12: VHIO098-T1-x03-16.029383-C1-Sel 4 Selumetinib 2
13: VHIO098-T1-x03-16.029384-C1-Sel 4 Selumetinib 2
14: VHIO098-T1-x03-16.029386-C1-Veh 4 Vehicle 2
There appears to be duplication depending on the “processing batch”. I need to confirm with Dimitra what exactly this was in reference to and, potentially, fill in the “NAs”. The meta data would suggest that all the “NAs” should be 1.
—> After talking to Dim, I can confirm that all of SLX-14906 consisted of samples processed in a different manner to the rest. For ease, let us remove these samples from the analysis.
rnaseq <- subset.PDX(rnaseq,rnaseq$meta$merged.lanes!=4)
Let us check again the mouse fractions w.r.t. all sequencing runs.
ggplot(rnaseq$meta[,.(mouse.library.size/(mouse.library.size+human.library.size),merged.lanes)]) + aes(x=factor(merged.lanes), fill = factor(merged.lanes), y = V1) + geom_boxplot() + geom_jitter(width=0.1)

Both of the above indicate that we have not lost sensitivity in reducing the our read lengths.
Cellularity changes
Let’s just see whether there is a difference in the PDXs cellularity as we saw changes with the Olaparib drug treatment.
x <- melt(rnaseq$meta,id.vars=c("Sample.name","PDX","Treatment"),measure.vars = c("mouse.library.size","human.library.size"))
x[,value:=value/sum(value),Sample.name]
ggplot(x[variable=="mouse.library.size"]) + aes(x=Treatment,y=value,fill=Treatment) + geom_boxplot() + theme(axis.text.x=element_text(angle=90,hjust=1)) + facet_wrap(~PDX,scales = "free_y")

There does not appear to be a systematic change in the cellularity with treatment. Note that selu is a far more targeted therapy than olap, and hence may not change the stroma-tumor fractions as much.
PCAs
pca <- pca.run(rnaseq$human)
pca <- cbind(rnaseq$meta,pca)
pca$merged.lanes <- factor(pca$merged.lanes)
ggpairs(pca, columns=c('PC1', 'PC2', 'PC3', "human.library.size"),mapping=aes(color=PDX), upper=list(continuous='cor'))

ggpairs(pca, columns=c('PC1', 'PC2', 'PC3', "human.library.size"),mapping=aes(color=Treatment), upper=list(continuous='cor'))

ggpairs(pca, columns=c('PC1', 'PC2', 'PC3', "human.library.size"),mapping=aes(color=merged.lanes), upper=list(continuous='cor'))

There appears a large batch effect associated with the sequencing. Outwith of that there is also some grouping based on pdx type, while nothing notable with regards to treatment.
rnaseq$meta[,.N,.(merged.lanes,PDX,Treatment)][order(merged.lanes)]
merged.lanes PDX Treatment N
1: 1 VHIO098OR Selumetinib 7
2: 1 VHIO098OR Vehicle 7
3: 1 HCI009 Vehicle 1
4: 1 VHIO098 Selumetinib 3
5: 1 VHIO098 Unknown 1
6: 1 STG139 Selumetinib 4
7: 1 HCI009 Selumetinib 2
8: 1 STG139 Vehicle 4
9: 1 STG316 Vehicle 1
10: 2 HCI009 Vehicle 3
11: 2 VHIO098 Selumetinib 1
12: 2 STG316 Selumetinib 2
13: 2 STG139 Vehicle 1
14: 2 VHIO098 Vehicle 1
15: 2 HCI009 Selumetinib 1
16: 3 HCI009 Vehicle 2
17: 3 HCI009 Selumetinib 1
18: 3 STG139 Selumetinib 1
19: 3 VHIO098 Vehicle 2
20: 3 STG316 Selumetinib 1
21: 3 STG316 Vehicle 1
merged.lanes PDX Treatment N
Let us repeat both the above PCAs using batch correction to account for the sequencing.
pca <- pca.prep(rnaseq$human)
pca <- with(rnaseq$meta,removeBatchEffect(pca,design = model.matrix(~ PDX + Treatment),batch = merged.lanes))
pca <- prcomp(t(pca),scale=T)
summary(pca)
Importance of components:
PC1 PC2 PC3 PC4 PC5 PC6 PC7 PC8 PC9 PC10 PC11 PC12 PC13 PC14 PC15 PC16 PC17 PC18 PC19 PC20
Standard deviation 22.5364 13.5307 11.3808 8.2155 5.07235 3.54701 2.87981 2.76189 2.49514 2.32141 2.09300 1.9501 1.90958 1.82024 1.73663 1.61807 1.58588 1.4480 1.37109 1.32881
Proportion of Variance 0.5079 0.1831 0.1295 0.0675 0.02573 0.01258 0.00829 0.00763 0.00623 0.00539 0.00438 0.0038 0.00365 0.00331 0.00302 0.00262 0.00252 0.0021 0.00188 0.00177
Cumulative Proportion 0.5079 0.6910 0.8205 0.8880 0.91372 0.92630 0.93459 0.94222 0.94844 0.95383 0.95821 0.9620 0.96566 0.96898 0.97199 0.97461 0.97713 0.9792 0.98110 0.98287
PC21 PC22 PC23 PC24 PC25 PC26 PC27 PC28 PC29 PC30 PC31 PC32 PC33 PC34 PC35 PC36 PC37 PC38 PC39
Standard deviation 1.28813 1.16859 1.11535 1.09041 1.06163 1.02163 0.98324 0.90228 0.89011 0.86423 0.81558 0.81330 0.74471 0.72684 0.71666 0.71209 0.67123 0.64245 0.60594
Proportion of Variance 0.00166 0.00137 0.00124 0.00119 0.00113 0.00104 0.00097 0.00081 0.00079 0.00075 0.00067 0.00066 0.00055 0.00053 0.00051 0.00051 0.00045 0.00041 0.00037
Cumulative Proportion 0.98453 0.98589 0.98714 0.98833 0.98945 0.99050 0.99146 0.99228 0.99307 0.99382 0.99448 0.99514 0.99570 0.99623 0.99674 0.99725 0.99770 0.99811 0.99848
PC40 PC41 PC42 PC43 PC44 PC45 PC46 PC47
Standard deviation 0.60359 0.57972 0.55428 0.53345 0.47942 1.001e-14 4.473e-15 3.181e-15
Proportion of Variance 0.00036 0.00034 0.00031 0.00028 0.00023 0.000e+00 0.000e+00 0.000e+00
Cumulative Proportion 0.99884 0.99918 0.99949 0.99977 1.00000 1.000e+00 1.000e+00 1.000e+00
pca <- cbind(rnaseq$meta,pca$x)
pca$merged.lanes <- factor(pca$merged.lanes)
ggpairs(pca, columns=c('PC1', 'PC2', 'PC3', "human.library.size"),mapping=aes(color=PDX), upper=list(continuous='cor'))

ggpairs(pca, columns=c('PC1', 'PC2', 'PC3', "human.library.size"),mapping=aes(color=Treatment), upper=list(continuous='cor'))

ggpairs(pca, columns=c('PC1', 'PC2', 'PC3', "human.library.size"),mapping=aes(color=merged.lanes), upper=list(continuous='cor'))

Given the construction of the meta data, it’s hard to remove the effect of the sequencing from the variables of interest. As such, we get only a small reduction in the sequencing dominating the variablility.
Let’s plot the different PDX arms individually.
for(pdx in unique(rnaseq$meta$PDX)){
x <- subset.PDX(rnaseq, rnaseq$meta[,pdx == PDX])
pca <- pca.run(x$human)
pca <- cbind(x$meta,pca)
pca$merged.lanes <- factor(pca$merged.lanes)
print(ggpairs(pca, columns=c('PC1', 'PC2', 'PC3', "human.library.size"),mapping=aes(color=Treatment,shape=merged.lanes), upper=list(continuous='cor')) + ggtitle(pdx))
}



We are buggered by the sequencing…. :(
Since its not obvious by the grouping, what the unknown sample is from, I will remove it.
rnaseq <- subset.PDX(rnaseq,rnaseq$meta$Treatment!="Unknown")
Key questions
- Genes of interest: EGFR, apoptotic genes (bcl2, mcl1, bax)
- Are there any systematic differences between the control and treated groups?
- Are there any traits/markers that define the speed with which resistance is devloped in the treated groups?
- Is resistance developed in different manners between the treated samples?
Model: ~ drug + pdx
All data
sequencing <- rnaseq$meta[,factor(merged.lanes)]
treatment <- rnaseq$meta[,Treatment]
pdx <- rnaseq$meta[,PDX]
d <- model.matrix(~ 0 + treatment + pdx + sequencing)
cont.matrix <- matrix(c(1,-1,rep(0,dim(d)[2]-2)), dim(d)[2], 1)
colnames(cont.matrix) <- c("Selu.minus.control")
rownames(cont.matrix) <- colnames(d)
cont.matrix
Selu.minus.control
treatmentSelumetinib 1
treatmentVehicle -1
pdxSTG139 0
pdxSTG316 0
pdxVHIO098 0
pdxVHIO098OR 0
sequencing2 0
sequencing3 0
#Perform DE
DE.data <- DE.run(rnaseq$human,d,2,cont.matrix = cont.matrix)


#Top DE genes table
DE <- topTable.annotated.DE(DE.data$efit,p.val = 0.05)
No DE genes
if(nrow(DE)!=0){
table(DE[,direction])
DE[direction=="up.reg",.(direction,ENSEMBL,SYMBOL,adj.P.Val,logFC)]
DE[direction=="down.reg",.(direction,ENSEMBL,SYMBOL,adj.P.Val,logFC)]
#Pheatmap w/ batch correction
i <- match(DE$ENSEMBL,rownames(DE.data$v$E))
y <- removeBatchEffect(DE.data$v$E[i,],design = model.matrix(~drug), batch= pdx)
labels.col <- rep("",nrow(rnaseq$meta))
labels.row <- DE$SYMBOL
ann.col <- as.data.frame(rnaseq$meta[,.(pdx,drug)])
rownames(ann.col) <- rnaseq$meta[,Sample.name]
pheatmap(y,labels_col=labels.col,labels_row=labels.row,annotation_col = ann.col,scale="row")
}
#GSEA - c6
gsea <- GSEA.run(DE.data$v,d,cont.matrix[,1],Hs.c6,0.05)
'select()' returned 1:many mapping between keys and columns
gsea[Direction=="Up",.(rn,NGenes,Direction,FDR)]
Empty data.table (0 rows) of 4 cols: rn,NGenes,Direction,FDR
gsea[Direction=="Down",.(rn,NGenes,Direction,FDR)]
Empty data.table (0 rows) of 4 cols: rn,NGenes,Direction,FDR
#GSEA - c2
gsea <- GSEA.run(DE.data$v,d,cont.matrix[,1],Hs.c2,0.05)
'select()' returned 1:many mapping between keys and columns
gsea[Direction=="Up",.(rn,NGenes,Direction,FDR)]
rn NGenes Direction FDR
1: NIKOLSKY_BREAST_CANCER_8Q23_Q24_AMPLICON 142 Up 0.03267419
gsea[Direction=="Down",.(rn,NGenes,Direction,FDR)]
rn NGenes Direction FDR
1: REACTOME_PEPTIDE_CHAIN_ELONGATION 85 Down 0.03267419
2: KEGG_RIBOSOME 85 Down 0.03267419
# ssGSEA
ssGSEA.data <- ssGSEA.run(DE.data$v$E,Hs.c6,d,cont.matrix=cont.matrix)
'select()' returned 1:many mapping between keys and columns
Error in .local(expr, gset.idx.list, ...) :
unused argument (rnaseq = TRUE)
The lack of any results is unsuprising as this statistical model is the most simplistic; not presuming that different models react differently to the drug, espcially with a resistant model included, is foolish. Also, the sequencing is dominating all the variability.
Genes of Interest
These genes were found in the scRNAseq data to be notable:
rr genes <- c(4, 1, ,1A,,3K8,1) ids <- mapIds(org.Hs.eg.db,keys=genes,keytype = ,column = , multiVals = )
'select()' returned 1:1 mapping between keys and columns
rr y <- DE.data\(v\)E[match(ids,rownames(DE.data$v)),] rownames(y) <- genes y <- removeBatchEffect(y,design = model.matrix(~treatment), batch=pdx, batch2 = sequencing) for(i in 1:length(ids)){ x <- y[i,] stripchart(x~treatment*pdx,vertical=TRUE,las=2,cex.axis=0.8,pch=16,col=1:2,method=,main=genes[i]) }







Shifts of mean w.r.t. PDX models
Repeat above with median (less affected by outliers)
Pathways of interest
Let us also check the LEF1 signature, which showed a response in the scRNA-seq data between response and resistence samples; a comparison we can’t perform due to sample numbers.
Shifts of mean w.r.t. PDX models
Repeat above with median (less affected by outliers)
Model: ~ drug:pdx
VHIO098
Only VHIO098-naive (Model: ~ drug)
VHI <- subset.PDX(rnaseq,rnaseq$meta[,PDX=="VHIO098" & Treatment!="Unknown"])
treatment <- VHI$meta[,Treatment]
sequencing <- VHI$meta[,factor(merged.lanes)]
#d <- model.matrix(~ 0 + treatment + sequencing)
d <- model.matrix(~ 0 + treatment) #<- Bad Ali
cont.matrix <- matrix(c(1,-1,rep(0,dim(d)[2]-2)), dim(d)[2], 1)
colnames(cont.matrix) <- c("Selu.minus.control")
rownames(cont.matrix) <- colnames(d)
cont.matrix
Selu.minus.control
treatmentSelumetinib 1
treatmentVehicle -1
#Perform DE
DE.data <- DE.run(VHI$human,d,2,cont.matrix = cont.matrix)


#Top DE genes table
DE <- topTable.annotated.DE(DE.data$efit,p.val = 0.5)
'select()' returned 1:many mapping between keys and columns
Only VHIO098OR (Model: ~ drug)
VHIO.OR <- subset.PDX(rnaseq,rnaseq$meta[,PDX=="VHIO098OR"])
treatment <- VHIO.OR$meta[,Treatment]
d <- model.matrix(~ 0 + treatment)
cont.matrix <- matrix(c(1,-1,rep(0,dim(d)[2]-2)), dim(d)[2], 1)
colnames(cont.matrix) <- c("Selu.minus.control")
rownames(cont.matrix) <- colnames(d)
cont.matrix
Selu.minus.control
treatmentSelumetinib 1
treatmentVehicle -1
#Perform DE
DE.data <- DE.run(VHIO.OR$human,d,2,cont.matrix = cont.matrix)


#Top DE genes table
DE <- topTable.annotated.DE(DE.data$efit,p.val = 0.05)
No DE genes
if(nrow(DE)!=0){
table(DE[,direction])
DE[direction=="up.reg",.(direction,ENSEMBL,SYMBOL,adj.P.Val,logFC)]
DE[direction=="down.reg",.(direction,ENSEMBL,SYMBOL,adj.P.Val,logFC)]
#Pheatmap w/ batch correction
i <- match(DE$ENSEMBL,rownames(DE.data$v$E))
y <- removeBatchEffect(DE.data$v$E[i,],design = model.matrix(~drug), batch= pdx)
labels.col <- rep("",nrow(VHIO.OR$meta))
labels.row <- DE$SYMBOL
ann.col <- as.data.frame(VHIO.OR$meta[,.(pdx,drug)])
rownames(ann.col) <- VHIO.OR$meta[,Sample.name]
pheatmap(y,labels_col=labels.col,labels_row=labels.row,annotation_col = ann.col,scale="row")
}
#GSEA - c2
gsea <- GSEA.run(DE.data$v,d,cont.matrix[,1],Hs.c2,0.05)
'select()' returned 1:many mapping between keys and columns
gsea[Direction=="Up",.(rn,NGenes,Direction,FDR)]
Empty data.table (0 rows) of 4 cols: rn,NGenes,Direction,FDR
gsea[Direction=="Down",.(rn,NGenes,Direction,FDR)]
rn NGenes Direction FDR
1: KEGG_RIBOSOME 84 Down 0.001011085
2: REACTOME_PEPTIDE_CHAIN_ELONGATION 83 Down 0.001011085
3: REACTOME_INFLUENZA_VIRAL_RNA_TRANSCRIPTION_AND_REPLICATION 98 Down 0.003603039
4: REACTOME_3_UTR_MEDIATED_TRANSLATIONAL_REGULATION 103 Down 0.017458050
5: REACTOME_SRP_DEPENDENT_COTRANSLATIONAL_PROTEIN_TARGETING_TO_MEMBRANE 106 Down 0.017458050
6: MOOTHA_VOXPHOS 85 Down 0.030650877
#GSEA - c6
gsea <- GSEA.run(DE.data$v,d,cont.matrix[,1],Hs.c6,0.05)
'select()' returned 1:many mapping between keys and columns
gsea[Direction=="Up",.(rn,NGenes,Direction,FDR)]
Empty data.table (0 rows) of 4 cols: rn,NGenes,Direction,FDR
gsea[Direction=="Down",.(rn,NGenes,Direction,FDR)]
Empty data.table (0 rows) of 4 cols: rn,NGenes,Direction,FDR
#ssGSEA - c6
ssGSEA.data <- ssGSEA.run(DE.data$v$E,Hs.c6,d,cont.matrix=cont.matrix)
'select()' returned 1:many mapping between keys and columns
Error in .local(expr, gset.idx.list, ...) :
unused argument (rnaseq = TRUE)
Only VHIO098 (w/ Selu) (Model: ~ PDX)
rr VHIO.OR <- subset.PDX(rnaseq,rnaseq\(meta[,PDX %in% c(\VHIO098\,\VHIO098OR\) & Treatment==\Selumetinib\ & merged.lanes==1]) model <- VHIO.OR\)meta[,PDX] d <- model.matrix(~ 0 + model) cont.matrix <- matrix(c(1,-1,rep(0,dim(d)[2]-2)), dim(d)[2], 1) colnames(cont.matrix) <- c(.minus.Naive) rownames(cont.matrix) <- colnames(d) cont.matrix
OR.minus.Naive
modelVHIO098 1
modelVHIO098OR -1
rr #Perform DE DE.data <- DE.run(VHIO.OR$human,d,2,cont.matrix = cont.matrix)


rr #Top DE genes table DE <- topTable.annotated.DE(DE.data$efit,p.val = 0.05)
'select()' returned 1:many mapping between keys and columns
rr if(nrow(DE)!=0){ table(DE[,direction]) DE[direction==.reg,.(direction,ENSEMBL,SYMBOL,adj.P.Val,logFC)] DE[direction==.reg,.(direction,ENSEMBL,SYMBOL,adj.P.Val,logFC)] #Pheatmap w/ batch correction i <- match(DE\(ENSEMBL,rownames(DE.data\)v\(E)) y <- DE.data\)v\(E[i,] labels.col <- rep(\\,nrow(VHIO.OR\)meta)) labels.row <- DE\(SYMBOL ann.col <- as.data.frame(VHIO.OR\)meta[,.(PDX)]) rownames(ann.col) <- VHIO.OR$meta[,Sample.name] pheatmap(y,labels_col=labels.col,labels_row=labels.row,annotation_col = ann.col,scale=) }

rr #GSEA - c2 gsea <- GSEA.run(DE.data$v,d,cont.matrix[,1],Hs.c2,0.05)
'select()' returned 1:many mapping between keys and columns
rr gsea[Direction==,.(rn,NGenes,Direction,FDR)] r gsea[Direction==,.(rn,NGenes,Direction,FDR)]
rr #GSEA - c6 gsea <- GSEA.run(DE.data$v,d,cont.matrix[,1],Hs.c6,0.05)
'select()' returned 1:many mapping between keys and columns
rr gsea[Direction==,.(rn,NGenes,Direction,FDR)]
rr gsea[Direction==,.(rn,NGenes,Direction,FDR)]
rr #ssGSEA - c6 ssGSEA.data <- ssGSEA.run(DE.data\(v\)E,Hs.c6,d,cont.matrix=cont.matrix)
'select()' returned 1:many mapping between keys and columns
The argument 'rnaseq' is deprecated and will be removed in the next release of GSVA. Please use the 'kcdf' argument instead.
Estimating GSVA scores for 189 gene sets.
Computing observed enrichment scores
Estimating ECDFs in microarray data with Gaussian kernels
Using parallel with 4 cores
|
| | 0%

rr #Top DE gene.sets table ssGSEA <- topTable.annotated.ssGSEA(ssGSEA.data$efit)
No DE genes
rr if(nrow(ssGSEA)!=0){ ssGSEA[direction==.reg,.(direction,gene.set,adj.P.Val,logFC)] ssGSEA[direction==.reg,.(direction,gene.set,adj.P.Val,logFC)] } if(nrow(ssGSEA)>1){ #Pheatmap w/ batch correction i <- match(ssGSEA\(gene.set,rownames(ssGSEA.data\)w)) labels.col <- rep(\,nrow(VHIO.OR\(meta)) labels.row <- ssGSEA\)gene.set ann.col <- as.data.frame(HCI\(meta[,.(treatment)]) rownames(ann.col) <- HCI\)meta[,Sample.name] pheatmap(ssGSEA.data$w[i,],labels_col=labels.col,labels_row=labels.row,annotation_col = ann.col,scale=) }
Other models
Only STG139 (Model: ~ drug)
STG139 <- subset.PDX(rnaseq,rnaseq$meta[,PDX=="STG139" & merged.lanes==1])
treatment <- STG139$meta[,Treatment]
d <- model.matrix(~ 0 + treatment)
cont.matrix <- matrix(c(1,-1,rep(0,dim(d)[2]-2)), dim(d)[2], 1)
colnames(cont.matrix) <- c("Selu.minus.control")
rownames(cont.matrix) <- colnames(d)
cont.matrix
#Perform DE
DE.data <- DE.run(STG139$human,d,2,cont.matrix = cont.matrix)
#Top DE genes table
DE <- topTable.annotated.DE(DE.data$efit,p.val = 0.05)
if(nrow(DE)!=0){
table(DE[,direction])
DE[direction=="up.reg",.(direction,ENSEMBL,SYMBOL,adj.P.Val,logFC)]
DE[direction=="down.reg",.(direction,ENSEMBL,SYMBOL,adj.P.Val,logFC)]
#Pheatmap w/ batch correction
i <- match(DE$ENSEMBL,rownames(DE.data$v$E))
y <- removeBatchEffect(DE.data$v$E[i,],design = model.matrix(~drug), batch= pdx)
labels.col <- rep("",nrow(STG139$meta))
labels.row <- DE$SYMBOL
ann.col <- as.data.frame(STG139$meta[,.(pdx,drug)])
rownames(ann.col) <- STG139$meta[,Sample.name]
pheatmap(y,labels_col=labels.col,labels_row=labels.row,annotation_col = ann.col,scale="row")
}
#GSEA - c2
gsea <- GSEA.run(DE.data$v,d,cont.matrix[,1],Hs.c2,0.05)
gsea[Direction=="Up",.(rn,NGenes,Direction,FDR)]
gsea[Direction=="Down",.(rn,NGenes,Direction,FDR)]
#GSEA - c6
gsea <- GSEA.run(DE.data$v,d,cont.matrix[,1],Hs.c6,0.05)
gsea[Direction=="Up",.(rn,NGenes,Direction,FDR)]
gsea[Direction=="Down",.(rn,NGenes,Direction,FDR)]
#ssGSEA - c6
ssGSEA.data <- ssGSEA.run(DE.data$v$E,Hs.c6,d,cont.matrix=cont.matrix)
#Top DE gene.sets table
ssGSEA <- topTable.annotated.ssGSEA(ssGSEA.data$efit)
if(nrow(ssGSEA)!=0){
ssGSEA[direction=="up.reg",.(direction,gene.set,adj.P.Val,logFC)]
ssGSEA[direction=="down.reg",.(direction,gene.set,adj.P.Val,logFC)]
}
if(nrow(ssGSEA)>1){
#Pheatmap w/ batch correction
i <- match(ssGSEA$gene.set,rownames(ssGSEA.data$w))
labels.col <- rep("",nrow(STG139$meta))
labels.row <- ssGSEA$gene.set
ann.col <- as.data.frame(HCI$meta[,.(treatment)])
rownames(ann.col) <- HCI$meta[,Sample.name]
pheatmap(ssGSEA.data$w[i,],labels_col=labels.col,labels_row=labels.row,annotation_col = ann.col,scale="row")
}
Only HCI009 (Model: ~ drug)
rr HCI <- subset.PDX(rnaseq,rnaseq\(meta[,PDX==\HCI009\]) treatment <- HCI\)meta[,Treatment] sequencing <- HCI$meta[,factor(merged.lanes)] d <- model.matrix(~ 0 + treatment + sequencing)
cont.matrix <- matrix(c(1,-1,rep(0,dim(d)[2]-2)), dim(d)[2], 1) colnames(cont.matrix) <- c(.minus.control) rownames(cont.matrix) <- colnames(d) cont.matrix
#Perform DE DE.data <- DE.run(HCI$human,d,2,cont.matrix = cont.matrix)
#Top DE genes table DE <- topTable.annotated.DE(DE.data$efit,p.val = 0.05) if(nrow(DE)!=0){ table(DE[,direction]) DE[direction==.reg,.(direction,ENSEMBL,SYMBOL,adj.P.Val,logFC)] DE[direction==.reg,.(direction,ENSEMBL,SYMBOL,adj.P.Val,logFC)]
#Pheatmap w/ batch correction i <- match(DE\(ENSEMBL,rownames(DE.data\)v\(E)) y <- removeBatchEffect(DE.data\)v\(E[i,],design = model.matrix(~drug), batch= pdx) labels.col <- rep(\\,nrow(rnaseq\)meta)) labels.row <- DE\(SYMBOL ann.col <- as.data.frame(rnaseq\)meta[,.(pdx,drug)]) rownames(ann.col) <- rnaseq$meta[,Sample.name] pheatmap(y,labels_col=labels.col,labels_row=labels.row,annotation_col = ann.col,scale=) }
#GSEA - c2 gsea <- GSEA.run(DE.data$v,d,cont.matrix[,1],Hs.c2,0.05) gsea[Direction==,.(rn,NGenes,Direction,FDR)] gsea[Direction==,.(rn,NGenes,Direction,FDR)]
#GSEA - c6 gsea <- GSEA.run(DE.data$v,d,cont.matrix[,1],Hs.c6,0.05) gsea[Direction==,.(rn,NGenes,Direction,FDR)] gsea[Direction==,.(rn,NGenes,Direction,FDR)]
#ssGSEA - c6 ssGSEA.data <- ssGSEA.run(DE.data\(v\)E,Hs.c6,d,cont.matrix=cont.matrix)
#Top DE gene.sets table ssGSEA <- topTable.annotated.ssGSEA(ssGSEA.data$efit) if(nrow(ssGSEA)!=0){ ssGSEA[direction==.reg,.(direction,gene.set,adj.P.Val,logFC)] ssGSEA[direction==.reg,.(direction,gene.set,adj.P.Val,logFC)] }
if(nrow(ssGSEA)>1){ #Pheatmap w/ batch correction i <- match(ssGSEA\(gene.set,rownames(ssGSEA.data\)w)) labels.col <- rep(\,nrow(HCI\(meta)) labels.row <- ssGSEA\)gene.set ann.col <- as.data.frame(HCI\(meta[,.(treatment)]) rownames(ann.col) <- HCI\)meta[,Sample.name] pheatmap(ssGSEA.data$w[i,],labels_col=labels.col,labels_row=labels.row,annotation_col = ann.col,scale=) }
LS0tCnRpdGxlOiAnUERYOiBEcnVnIHRyYWlscycKYXV0aG9yOiAiQWxpc3RhaXIgTWFydGluIgpkYXRlOiAnYHIgZm9ybWF0KFN5cy50aW1lKCksICJMYXN0IG1vZGlmaWVkOiAlZCAlYiAlWSIpYCcKb3V0cHV0OgogIHBkZl9kb2N1bWVudDoKICAgIHRvYzogeWVzCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKc3VidGl0bGU6IFNlbHUKbGF5b3V0OiBwYWdlCi0tLQoKIyBMb2FkIGxpYnJhcmllcyBhbmQgZGF0YQpgYGB7ciwgbWVzc2FnZT1GLCB3YXJuaW5nPUZ9CnJvb3QuZGlyIDwtICJ+L09uZURyaXZlL3Byb2plY3RzLyIKcHJvamVjdC5kaXIgPC0gcGFzdGUwKHJvb3QuZGlyLCJQRFgvIikKc291cmNlKHBhc3RlMChyb290LmRpciwiUi51dGlscy9STkFTRVEudXRpbHMuUiIpKQpzb3VyY2UocGFzdGUwKHByb2plY3QuZGlyLCJzcmMvbG9hZC5QRFguUiIpKQoKcm5hc2VxIDwtIGdldC5QRFgoKQptZXRhIDwtIGxvYWQubWV0YSgpCgptZXRhIDwtIHN1YnNldC5tZXRhKG1ldGEsbWV0YVsscHJvamVjdD09ImRydWcuc2VsdSJdKQpybmFzZXEgPC0gc3Vic2V0LlBEWChybmFzZXEsIHJuYXNlcSRtZXRhWyxTYW1wbGUubmFtZV0gJWluJSBtZXRhWyxTYW1wbGUubmFtZV0pCmBgYAoKIyBRQwoKYGBge3IsZmlnLndpZHRoPTEyLGZpZy5oZWlnaHQ9Nn0KcmVhZC5kZXB0aC5wbG90cyhybmFzZXEkbWV0YSkKYGBgCgpXZSBzaG91bGQgcmVtb3ZlIHRoZSBydW5zIHRoYXQgY29udGFpbiB2ZXJ5IGZldyByZWFkcyBiZWZvcmUgd2UgbWVyZ2Ugb3RoZXJ3aXNlIHRoZXkgY291bGQgYmlhcyB0aGUgc3Vic2VxdWVudCBhbmFseXNpcy4gCgpgYGB7cn0Kcm5hc2VxIDwtIHN1YnNldC5QRFgocm5hc2VxLCBybmFzZXEkbWV0YVssaHVtYW4ubGlicmFyeS5zaXplPjFFNl0pCmBgYAoKUmVwZWF0IFFDIHBsb3RzOgoKYGBge3IsZmlnLndpZHRoPTEyLGZpZy5oZWlnaHQ9Nn0KcmVhZC5kZXB0aC5wbG90cyhybmFzZXEkbWV0YSkKYGBgCgpgYGB7cn0Kcm5hc2VxIDwtIG1lcmdlLlBEWChybmFzZXEpCnJuYXNlcSRtZXRhIDwtIG1lcmdlKHJuYXNlcSRtZXRhLG1ldGEsc29ydD1GKQp1bmlxdWUocm5hc2VxJG1ldGFbLC4obWVyZ2VkLmxhbmVzLGFzLm51bWVyaWMoYXMuZmFjdG9yKG1lcmdlZC5sYW5lcykpKV0pCnJuYXNlcSRtZXRhWyxtZXJnZWQubGFuZXM6PWFzLm51bWVyaWMoYXMuZmFjdG9yKG1lcmdlZC5sYW5lcykpXQpgYGAKCldoYXQgc2FtcGxlcyByZW1haW4gYWZ0ZXIgYWxsIHRoYXQgUUM6CgpgYGB7cn0KdGFibGUodW5pcXVlKHJuYXNlcSRtZXRhWywuKFBEWCxUcmVhdG1lbnQsTW91c2UpXSlbLC4oUERYLFRyZWF0bWVudCldKQpgYGAKCk5vdGUgdGhhdCB0aGUgVkhJTzA5OCBzYW1wbGVzIGNvbnRhaW4gZHVwbGljYXRlcyAoYXMgbm90ZWQgYnkgbWljZSBudW1iZXJzKS4KCmBgYHtyfQpybmFzZXEkbWV0YVssLk4sLihNb3VzZSxQRFgsVHJlYXRtZW50KV1bTj4xXQpgYGAKCkxldCdzIHVzZSB0aGVzZSBkdXBsaWNhdGVzIHRvIHNlZSBpZiB0aGUgYXNzaWdubWVudCBvZiBodW1hbiBhbmQgbW91c2UgcmVhZHMgc3VmZmVyZWQgYnkgcmVkdWNpbmcgdG8gU0U1MCBzZXF1ZW5jaW5nIApOb3RlOiBtZXJnZWQubGFuZT09MSAtLT4gU0xYLTE0MDgyOyB3aGljaCBpcyBTRTUwKQoKYGBge3J9CnggPC0gcm5hc2VxJG1ldGFbTW91c2UgJWluJSBybmFzZXEkbWV0YVssLk4sLihNb3VzZSxQRFgsVHJlYXRtZW50KV1bTj4xLE1vdXNlXV1bb3JkZXIoTW91c2UpLC4oU2FtcGxlLm5hbWUsTW91c2UsbWVyZ2VkLmxhbmVzLG1vdXNlLmxpYnJhcnkuc2l6ZS8obW91c2UubGlicmFyeS5zaXplK2h1bWFuLmxpYnJhcnkuc2l6ZSkpXQpnZ3Bsb3QoeCkgKyBhZXMoeD1Nb3VzZSx5PVY0LGNvbG91cj1mYWN0b3IobWVyZ2VkLmxhbmVzKSkgKyBnZW9tX3BvaW50KHNpemU9NSkgKyB0aGVtZV93c2ooKSArIGNvb3JkX2ZsaXAoKQpgYGAKClRoZXJlIGRvZXMgbm90IGFwcGVhciB0byBiZSBhIHNpZ25pZmdhbnQgY2hhbmdlIGluIHRoZSBtb3VzZSBmcmFjdGlvbiBkdWUgdG8gc2VxdWVuY2luZy4gSG93ZXZlciwgbGFuZSA0IHRoYXQgd2hpY2ggY29udGFpbnMgYWxsIHRoZSBkdXBsaWNhdGVzIChuZXdzISksIGhhcyBjb25zaXN0YW50bHkgbG93ZXIgYW1vdW50cyBvZiBtb3VzZS4gSSBkbyBub3Qga25vdyB3aHkgYWxsIHRoZSBkdXBsaWNhdGVzIGFyZSBmb3VuZCB3aXRoaW4gU0xYLTE0OTA2LiBBcmUgYWxsIG9mIFNMWC0xNDkwNiBkdXBsaWNhdGVzPwoKYGBge3J9CnJuYXNlcSRtZXRhW01vdXNlICVpbiUgcm5hc2VxJG1ldGFbbWVyZ2VkLmxhbmVzPT00LE1vdXNlXV1bb3JkZXIoTW91c2UpLC4oU2FtcGxlLm5hbWUsbWVyZ2VkLmxhbmVzLFRyZWF0bWVudCxQcm9jZXNzaW5nLmJhdGNoKV0KYGBgCgpUaGVyZSBhcHBlYXJzIHRvIGJlIGR1cGxpY2F0aW9uIGRlcGVuZGluZyBvbiB0aGUgInByb2Nlc3NpbmcgYmF0Y2giLiBJIG5lZWQgdG8gY29uZmlybSB3aXRoIERpbWl0cmEgd2hhdCBleGFjdGx5IHRoaXMgd2FzIGluIHJlZmVyZW5jZSB0byBhbmQsIHBvdGVudGlhbGx5LCBmaWxsIGluIHRoZSAiTkFzIi4gVGhlIG1ldGEgZGF0YSB3b3VsZCBzdWdnZXN0IHRoYXQgYWxsIHRoZSAiTkFzIiBzaG91bGQgYmUgMS4KCi0tLT4gQWZ0ZXIgdGFsa2luZyB0byBEaW0sIEkgY2FuIGNvbmZpcm0gdGhhdCBhbGwgb2YgU0xYLTE0OTA2IGNvbnNpc3RlZCBvZiBzYW1wbGVzIHByb2Nlc3NlZCBpbiBhIGRpZmZlcmVudCBtYW5uZXIgdG8gdGhlIHJlc3QuIEZvciBlYXNlLCBsZXQgdXMgcmVtb3ZlIHRoZXNlIHNhbXBsZXMgZnJvbSB0aGUgYW5hbHlzaXMuCgpgYGB7cn0Kcm5hc2VxIDwtIHN1YnNldC5QRFgocm5hc2VxLHJuYXNlcSRtZXRhJG1lcmdlZC5sYW5lcyE9NCkKYGBgCgpMZXQgdXMgY2hlY2sgYWdhaW4gdGhlIG1vdXNlIGZyYWN0aW9ucyB3LnIudC4gYWxsIHNlcXVlbmNpbmcgcnVucy4gCgpgYGB7cn0KZ2dwbG90KHJuYXNlcSRtZXRhWywuKG1vdXNlLmxpYnJhcnkuc2l6ZS8obW91c2UubGlicmFyeS5zaXplK2h1bWFuLmxpYnJhcnkuc2l6ZSksbWVyZ2VkLmxhbmVzKV0pICsgYWVzKHg9ZmFjdG9yKG1lcmdlZC5sYW5lcyksIGZpbGwgPSBmYWN0b3IobWVyZ2VkLmxhbmVzKSwgeSA9IFYxKSArIGdlb21fYm94cGxvdCgpICsgZ2VvbV9qaXR0ZXIod2lkdGg9MC4xKQpgYGAKCkJvdGggb2YgdGhlIGFib3ZlIGluZGljYXRlIHRoYXQgd2UgaGF2ZSBub3QgbG9zdCBzZW5zaXRpdml0eSBpbiByZWR1Y2luZyB0aGUgb3VyIHJlYWQgbGVuZ3Rocy4KCgojIENlbGx1bGFyaXR5IGNoYW5nZXMKCkxldCdzIGp1c3Qgc2VlIHdoZXRoZXIgdGhlcmUgaXMgYSBkaWZmZXJlbmNlIGluIHRoZSBQRFhzIGNlbGx1bGFyaXR5IGFzIHdlIHNhdyBjaGFuZ2VzIHdpdGggdGhlIE9sYXBhcmliIGRydWcgdHJlYXRtZW50LgoKYGBge3J9CnggPC0gbWVsdChybmFzZXEkbWV0YSxpZC52YXJzPWMoIlNhbXBsZS5uYW1lIiwiUERYIiwiVHJlYXRtZW50IiksbWVhc3VyZS52YXJzID0gYygibW91c2UubGlicmFyeS5zaXplIiwiaHVtYW4ubGlicmFyeS5zaXplIikpCnhbLHZhbHVlOj12YWx1ZS9zdW0odmFsdWUpLFNhbXBsZS5uYW1lXQpnZ3Bsb3QoeFt2YXJpYWJsZT09Im1vdXNlLmxpYnJhcnkuc2l6ZSJdKSArIGFlcyh4PVRyZWF0bWVudCx5PXZhbHVlLGZpbGw9VHJlYXRtZW50KSArIGdlb21fYm94cGxvdCgpICsgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTkwLGhqdXN0PTEpKSArIGZhY2V0X3dyYXAoflBEWCxzY2FsZXMgPSAiZnJlZV95IikKYGBgCgpUaGVyZSBkb2VzIG5vdCBhcHBlYXIgdG8gYmUgYSBzeXN0ZW1hdGljIGNoYW5nZSBpbiB0aGUgY2VsbHVsYXJpdHkgd2l0aCB0cmVhdG1lbnQuIE5vdGUgdGhhdCBzZWx1IGlzIGEgZmFyIG1vcmUgdGFyZ2V0ZWQgdGhlcmFweSB0aGFuIG9sYXAsIGFuZCBoZW5jZSBtYXkgbm90IGNoYW5nZSB0aGUgc3Ryb21hLXR1bW9yIGZyYWN0aW9ucyBhcyBtdWNoLgoKIyBQQ0FzCgpgYGB7cn0KcGNhIDwtIHBjYS5ydW4ocm5hc2VxJGh1bWFuKQpwY2EgPC0gY2JpbmQocm5hc2VxJG1ldGEscGNhKQpwY2EkbWVyZ2VkLmxhbmVzIDwtIGZhY3RvcihwY2EkbWVyZ2VkLmxhbmVzKQpnZ3BhaXJzKHBjYSwgY29sdW1ucz1jKCdQQzEnLCAnUEMyJywgJ1BDMycsICJodW1hbi5saWJyYXJ5LnNpemUiKSxtYXBwaW5nPWFlcyhjb2xvcj1QRFgpLCB1cHBlcj1saXN0KGNvbnRpbnVvdXM9J2NvcicpKQpnZ3BhaXJzKHBjYSwgY29sdW1ucz1jKCdQQzEnLCAnUEMyJywgJ1BDMycsICJodW1hbi5saWJyYXJ5LnNpemUiKSxtYXBwaW5nPWFlcyhjb2xvcj1UcmVhdG1lbnQpLCB1cHBlcj1saXN0KGNvbnRpbnVvdXM9J2NvcicpKQpnZ3BhaXJzKHBjYSwgY29sdW1ucz1jKCdQQzEnLCAnUEMyJywgJ1BDMycsICJodW1hbi5saWJyYXJ5LnNpemUiKSxtYXBwaW5nPWFlcyhjb2xvcj1tZXJnZWQubGFuZXMpLCB1cHBlcj1saXN0KGNvbnRpbnVvdXM9J2NvcicpKSAgCmBgYAoKVGhlcmUgYXBwZWFycyBhIGxhcmdlIGJhdGNoIGVmZmVjdCBhc3NvY2lhdGVkIHdpdGggdGhlIHNlcXVlbmNpbmcuIE91dHdpdGggb2YgdGhhdCB0aGVyZSBpcyBhbHNvIHNvbWUgZ3JvdXBpbmcgYmFzZWQgb24gcGR4IHR5cGUsIHdoaWxlIG5vdGhpbmcgbm90YWJsZSB3aXRoIHJlZ2FyZHMgdG8gdHJlYXRtZW50LgoKYGBge3J9CnJuYXNlcSRtZXRhWywuTiwuKG1lcmdlZC5sYW5lcyxQRFgsVHJlYXRtZW50KV1bb3JkZXIobWVyZ2VkLmxhbmVzKV0KYGBgCgpMZXQgdXMgcmVwZWF0IGJvdGggdGhlIGFib3ZlIFBDQXMgdXNpbmcgYmF0Y2ggY29ycmVjdGlvbiB0byBhY2NvdW50IGZvciB0aGUgc2VxdWVuY2luZy4KCmBgYHtyfQpwY2EgPC0gcGNhLnByZXAocm5hc2VxJGh1bWFuKQpwY2EgPC0gd2l0aChybmFzZXEkbWV0YSxyZW1vdmVCYXRjaEVmZmVjdChwY2EsZGVzaWduID0gbW9kZWwubWF0cml4KH4gUERYICsgVHJlYXRtZW50KSxiYXRjaCA9IG1lcmdlZC5sYW5lcykpCnBjYSA8LSBwcmNvbXAodChwY2EpLHNjYWxlPVQpCnN1bW1hcnkocGNhKQpwY2EgPC0gY2JpbmQocm5hc2VxJG1ldGEscGNhJHgpCnBjYSRtZXJnZWQubGFuZXMgPC0gZmFjdG9yKHBjYSRtZXJnZWQubGFuZXMpCmdncGFpcnMocGNhLCBjb2x1bW5zPWMoJ1BDMScsICdQQzInLCAnUEMzJywgImh1bWFuLmxpYnJhcnkuc2l6ZSIpLG1hcHBpbmc9YWVzKGNvbG9yPVBEWCksIHVwcGVyPWxpc3QoY29udGludW91cz0nY29yJykpCmdncGFpcnMocGNhLCBjb2x1bW5zPWMoJ1BDMScsICdQQzInLCAnUEMzJywgImh1bWFuLmxpYnJhcnkuc2l6ZSIpLG1hcHBpbmc9YWVzKGNvbG9yPVRyZWF0bWVudCksIHVwcGVyPWxpc3QoY29udGludW91cz0nY29yJykpCmdncGFpcnMocGNhLCBjb2x1bW5zPWMoJ1BDMScsICdQQzInLCAnUEMzJywgImh1bWFuLmxpYnJhcnkuc2l6ZSIpLG1hcHBpbmc9YWVzKGNvbG9yPW1lcmdlZC5sYW5lcyksIHVwcGVyPWxpc3QoY29udGludW91cz0nY29yJykpICAKYGBgCgpHaXZlbiB0aGUgY29uc3RydWN0aW9uIG9mIHRoZSBtZXRhIGRhdGEsIGl0J3MgaGFyZCB0byByZW1vdmUgdGhlIGVmZmVjdCBvZiB0aGUgc2VxdWVuY2luZyBmcm9tIHRoZSB2YXJpYWJsZXMgb2YgaW50ZXJlc3QuIEFzIHN1Y2gsIHdlIGdldCBvbmx5IGEgc21hbGwgcmVkdWN0aW9uIGluIHRoZSBzZXF1ZW5jaW5nIGRvbWluYXRpbmcgdGhlIHZhcmlhYmxpbGl0eS4KCkxldCdzIHBsb3QgdGhlIGRpZmZlcmVudCBQRFggYXJtcyBpbmRpdmlkdWFsbHkuCgpgYGB7cn0KZm9yKHBkeCBpbiB1bmlxdWUocm5hc2VxJG1ldGEkUERYKSl7CiAgeCA8LSBzdWJzZXQuUERYKHJuYXNlcSwgcm5hc2VxJG1ldGFbLHBkeCA9PSBQRFhdKQogIHBjYSA8LSBwY2EucnVuKHgkaHVtYW4pCiAgcGNhIDwtIGNiaW5kKHgkbWV0YSxwY2EpCiAgcGNhJG1lcmdlZC5sYW5lcyA8LSBmYWN0b3IocGNhJG1lcmdlZC5sYW5lcykKICBwcmludChnZ3BhaXJzKHBjYSwgY29sdW1ucz1jKCdQQzEnLCAnUEMyJywgJ1BDMycsICJodW1hbi5saWJyYXJ5LnNpemUiKSxtYXBwaW5nPWFlcyhjb2xvcj1UcmVhdG1lbnQsc2hhcGU9bWVyZ2VkLmxhbmVzKSwgdXBwZXI9bGlzdChjb250aW51b3VzPSdjb3InKSkgICsgZ2d0aXRsZShwZHgpKQp9CmBgYAoKCldlIGFyZSBidWdnZXJlZCBieSB0aGUgc2VxdWVuY2luZy4uLi4gOigKClNpbmNlIGl0cyBub3Qgb2J2aW91cyBieSB0aGUgZ3JvdXBpbmcsIHdoYXQgdGhlIHVua25vd24gc2FtcGxlIGlzIGZyb20sIEkgd2lsbCByZW1vdmUgaXQuCgpgYGB7cn0Kcm5hc2VxIDwtIHN1YnNldC5QRFgocm5hc2VxLHJuYXNlcSRtZXRhJFRyZWF0bWVudCE9IlVua25vd24iKQpgYGAKCiMgS2V5IHF1ZXN0aW9ucwoKKiBHZW5lcyBvZiBpbnRlcmVzdDogRUdGUiwgYXBvcHRvdGljIGdlbmVzIChiY2wyLCBtY2wxLCBiYXgpCiogQXJlIHRoZXJlIGFueSBzeXN0ZW1hdGljIGRpZmZlcmVuY2VzIGJldHdlZW4gdGhlIGNvbnRyb2wgYW5kIHRyZWF0ZWQgZ3JvdXBzPwoqIEFyZSB0aGVyZSBhbnkgdHJhaXRzL21hcmtlcnMgdGhhdCBkZWZpbmUgdGhlIHNwZWVkIHdpdGggd2hpY2ggcmVzaXN0YW5jZSBpcyBkZXZsb3BlZCBpbiB0aGUgdHJlYXRlZCBncm91cHM/CiogSXMgcmVzaXN0YW5jZSBkZXZlbG9wZWQgaW4gZGlmZmVyZW50IG1hbm5lcnMgYmV0d2VlbiB0aGUgdHJlYXRlZCBzYW1wbGVzPwoKIyBNb2RlbDogfiBkcnVnICsgcGR4CgojIyBBbGwgZGF0YQoKYGBge3J9CnNlcXVlbmNpbmcgPC0gcm5hc2VxJG1ldGFbLGZhY3RvcihtZXJnZWQubGFuZXMpXQp0cmVhdG1lbnQgPC0gcm5hc2VxJG1ldGFbLFRyZWF0bWVudF0KcGR4IDwtIHJuYXNlcSRtZXRhWyxQRFhdCmQgPC0gbW9kZWwubWF0cml4KH4gMCArIHRyZWF0bWVudCArIHBkeCArIHNlcXVlbmNpbmcpCgpjb250Lm1hdHJpeCA8LSBtYXRyaXgoYygxLC0xLHJlcCgwLGRpbShkKVsyXS0yKSksIGRpbShkKVsyXSwgMSkKY29sbmFtZXMoY29udC5tYXRyaXgpIDwtIGMoIlNlbHUubWludXMuY29udHJvbCIpCnJvd25hbWVzKGNvbnQubWF0cml4KSA8LSBjb2xuYW1lcyhkKQpjb250Lm1hdHJpeAoKI1BlcmZvcm0gREUKREUuZGF0YSA8LSBERS5ydW4ocm5hc2VxJGh1bWFuLGQsMixjb250Lm1hdHJpeCA9IGNvbnQubWF0cml4KQoKI1RvcCBERSBnZW5lcyB0YWJsZQpERSA8LSB0b3BUYWJsZS5hbm5vdGF0ZWQuREUoREUuZGF0YSRlZml0LHAudmFsID0gMC4wNSkKaWYobnJvdyhERSkhPTApewogIHRhYmxlKERFWyxkaXJlY3Rpb25dKQogIERFW2RpcmVjdGlvbj09InVwLnJlZyIsLihkaXJlY3Rpb24sRU5TRU1CTCxTWU1CT0wsYWRqLlAuVmFsLGxvZ0ZDKV0KICBERVtkaXJlY3Rpb249PSJkb3duLnJlZyIsLihkaXJlY3Rpb24sRU5TRU1CTCxTWU1CT0wsYWRqLlAuVmFsLGxvZ0ZDKV0KCiNQaGVhdG1hcCB3LyBiYXRjaCBjb3JyZWN0aW9uCiAgaSA8LSBtYXRjaChERSRFTlNFTUJMLHJvd25hbWVzKERFLmRhdGEkdiRFKSkKICB5IDwtIHJlbW92ZUJhdGNoRWZmZWN0KERFLmRhdGEkdiRFW2ksXSxkZXNpZ24gPSBtb2RlbC5tYXRyaXgofmRydWcpLCBiYXRjaD0gcGR4KQogIGxhYmVscy5jb2wgPC0gcmVwKCIiLG5yb3cocm5hc2VxJG1ldGEpKQogIGxhYmVscy5yb3cgPC0gREUkU1lNQk9MCiAgYW5uLmNvbCA8LSBhcy5kYXRhLmZyYW1lKHJuYXNlcSRtZXRhWywuKHBkeCxkcnVnKV0pCiAgcm93bmFtZXMoYW5uLmNvbCkgPC0gcm5hc2VxJG1ldGFbLFNhbXBsZS5uYW1lXQogIHBoZWF0bWFwKHksbGFiZWxzX2NvbD1sYWJlbHMuY29sLGxhYmVsc19yb3c9bGFiZWxzLnJvdyxhbm5vdGF0aW9uX2NvbCA9IGFubi5jb2wsc2NhbGU9InJvdyIpCn0KCiNHU0VBIC0gYzYKZ3NlYSA8LSBHU0VBLnJ1bihERS5kYXRhJHYsZCxjb250Lm1hdHJpeFssMV0sSHMuYzYsMC4wNSkKZ3NlYVtEaXJlY3Rpb249PSJVcCIsLihybixOR2VuZXMsRGlyZWN0aW9uLEZEUildCmdzZWFbRGlyZWN0aW9uPT0iRG93biIsLihybixOR2VuZXMsRGlyZWN0aW9uLEZEUildCgojR1NFQSAtIGMyCmdzZWEgPC0gR1NFQS5ydW4oREUuZGF0YSR2LGQsY29udC5tYXRyaXhbLDFdLEhzLmMyLDAuMDUpCmdzZWFbRGlyZWN0aW9uPT0iVXAiLC4ocm4sTkdlbmVzLERpcmVjdGlvbixGRFIpXQpnc2VhW0RpcmVjdGlvbj09IkRvd24iLC4ocm4sTkdlbmVzLERpcmVjdGlvbixGRFIpXQoKIyBzc0dTRUEKc3NHU0VBLmRhdGEgPC0gc3NHU0VBLnJ1bihERS5kYXRhJHYkRSxIcy5jNixkLGNvbnQubWF0cml4PWNvbnQubWF0cml4KQoKI1RvcCBERSBnZW5lLnNldHMgdGFibGUKc3NHU0VBIDwtIHRvcFRhYmxlLmFubm90YXRlZC5zc0dTRUEoc3NHU0VBLmRhdGEkZWZpdCkKaWYobnJvdyhzc0dTRUEpIT0wKXsKICBzc0dTRUFbZGlyZWN0aW9uPT0idXAucmVnIiwuKGRpcmVjdGlvbixnZW5lLnNldCxhZGouUC5WYWwsbG9nRkMpXQogIHNzR1NFQVtkaXJlY3Rpb249PSJkb3duLnJlZyIsLihkaXJlY3Rpb24sZ2VuZS5zZXQsYWRqLlAuVmFsLGxvZ0ZDKV0KICAKICAjUGhlYXRtYXAgdy8gYmF0Y2ggY29ycmVjdGlvbgogIGkgPC0gbWF0Y2goc3NHU0VBJGdlbmUuc2V0LHJvd25hbWVzKHNzR1NFQS5kYXRhJHcpKQogIHkgPC0gcmVtb3ZlQmF0Y2hFZmZlY3Qoc3NHU0VBLmRhdGEkd1tpLF0sZGVzaWduID0gbW9kZWwubWF0cml4KH5kcnVnKSwgYmF0Y2g9cGR4KQogIGxhYmVscy5jb2wgPC0gcmVwKCIiLG5yb3cocm5hc2VxJG1ldGEpKQogIGxhYmVscy5yb3cgPC0gc3NHU0VBJGdlbmUuc2V0CiAgYW5uLmNvbCA8LSBhcy5kYXRhLmZyYW1lKHJuYXNlcSRtZXRhWywuKHBkeCxkcnVnKV0pCiAgcm93bmFtZXMoYW5uLmNvbCkgPC0gcm5hc2VxJG1ldGFbLFNhbXBsZS5uYW1lXQogIHBoZWF0bWFwKHksbGFiZWxzX2NvbD1sYWJlbHMuY29sLGxhYmVsc19yb3c9bGFiZWxzLnJvdyxhbm5vdGF0aW9uX2NvbCA9IGFubi5jb2wsc2NhbGU9InJvdyIpCn0KYGBgCgpUaGUgbGFjayBvZiBhbnkgcmVzdWx0cyBpcyB1bnN1cHJpc2luZyBhcyB0aGlzIHN0YXRpc3RpY2FsIG1vZGVsIGlzIHRoZSBtb3N0IHNpbXBsaXN0aWM7IG5vdCBwcmVzdW1pbmcgdGhhdCBkaWZmZXJlbnQgbW9kZWxzIHJlYWN0IGRpZmZlcmVudGx5IHRvIHRoZSBkcnVnLCBlc3BjaWFsbHkgd2l0aCBhIHJlc2lzdGFudCBtb2RlbCBpbmNsdWRlZCwgaXMgZm9vbGlzaC4gQWxzbywgdGhlIHNlcXVlbmNpbmcgaXMgZG9taW5hdGluZyBhbGwgdGhlIHZhcmlhYmlsaXR5LgoKIyMjIEdlbmVzIG9mIEludGVyZXN0CgpUaGVzZSBnZW5lcyB3ZXJlIGZvdW5kIGluIHRoZSBzY1JOQXNlcSBkYXRhIHRvIGJlIG5vdGFibGU6CgoKYGBge3J9CmdlbmVzIDwtIGMoIktMRjQiLCAiSVJGMSIsICJORktCSUEiLCJDREtOMUEiLCJDRUJQRCIsIk1BUDNLOCIsIkVGTkExIikKaWRzIDwtIG1hcElkcyhvcmcuSHMuZWcuZGIsa2V5cz1nZW5lcyxrZXl0eXBlID0gIlNZTUJPTCIsY29sdW1uID0gIkVOU0VNQkwiLCBtdWx0aVZhbHMgPSAiZmlyc3QiKQp5IDwtIERFLmRhdGEkdiRFW21hdGNoKGlkcyxyb3duYW1lcyhERS5kYXRhJHYpKSxdCnJvd25hbWVzKHkpIDwtIGdlbmVzCnkgPC0gcmVtb3ZlQmF0Y2hFZmZlY3QoeSxkZXNpZ24gPSBtb2RlbC5tYXRyaXgofnRyZWF0bWVudCksIGJhdGNoPXBkeCwgYmF0Y2gyID0gc2VxdWVuY2luZykKCmZvcihpIGluIDE6bGVuZ3RoKGlkcykpewogIHggPC0geVtpLF0KICBzdHJpcGNoYXJ0KHh+dHJlYXRtZW50KnBkeCx2ZXJ0aWNhbD1UUlVFLGxhcz0yLGNleC5heGlzPTAuOCxwY2g9MTYsY29sPTE6MixtZXRob2Q9ImppdHRlciIsbWFpbj1nZW5lc1tpXSkKfQpgYGAKClNoaWZ0cyBvZiBtZWFuIHcuci50LiBQRFggbW9kZWxzCgpgYGB7cn0KeCA8LSBhcHBseSh5LDEsZnVuY3Rpb24oeCkgYXMubnVtZXJpYyhieSh4LGludGVyYWN0aW9uKHRyZWF0bWVudCxwZHgpLG1lYW4pKSkKeCA8LSB4W3NlcSgxLGJ5PTIsbGVuZ3RoLm91dCA9IGxlbmd0aCh1bmlxdWUocGR4KSkpLF0gLSB4W3NlcSgyLGJ5PTIsbGVuZ3RoLm91dCA9IGxlbmd0aCh1bmlxdWUocGR4KSkpLF0Kcm93bmFtZXMoeCkgPC0gc29ydCh1bmlxdWUocGR4KSkKeCA8LSBhcy5kYXRhLnRhYmxlKG1lbHQoeCkpCmdncGxvdCh4KSArIGFlcyh4PVZhcjEseT12YWx1ZSkgKyBnZW9tX2NvbCgpICsgZmFjZXRfd3JhcCh+VmFyMikgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkKYGBgCgpSZXBlYXQgYWJvdmUgd2l0aCBtZWRpYW4gKGxlc3MgYWZmZWN0ZWQgYnkgb3V0bGllcnMpCgpgYGB7cn0KeCA8LSBhcHBseSh5LDEsZnVuY3Rpb24oeCkgYXMubnVtZXJpYyhieSh4LGludGVyYWN0aW9uKHRyZWF0bWVudCxwZHgpLG1lZGlhbikpKQp4IDwtIHhbc2VxKDEsYnk9MixsZW5ndGgub3V0ID0gbGVuZ3RoKHVuaXF1ZShwZHgpKSksXSAtIHhbc2VxKDIsYnk9MixsZW5ndGgub3V0ID0gbGVuZ3RoKHVuaXF1ZShwZHgpKSksXQpyb3duYW1lcyh4KSA8LSBzb3J0KHVuaXF1ZShwZHgpKQp4IDwtIGFzLmRhdGEudGFibGUobWVsdCh4KSkKZ2dwbG90KHgpICsgYWVzKHg9VmFyMSx5PXZhbHVlKSArIGdlb21fY29sKCkgKyBmYWNldF93cmFwKH5WYXIyKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApKQpgYGAKCiMjIyBQYXRod2F5cyBvZiBpbnRlcmVzdAoKTGV0IHVzIGFsc28gY2hlY2sgdGhlIExFRjEgc2lnbmF0dXJlLCB3aGljaCBzaG93ZWQgYSByZXNwb25zZSBpbiB0aGUgc2NSTkEtc2VxIGRhdGEgYmV0d2VlbiByZXNwb25zZSBhbmQgcmVzaXN0ZW5jZSBzYW1wbGVzOyBhIGNvbXBhcmlzb24gd2UgY2FuJ3QgcGVyZm9ybSBkdWUgdG8gc2FtcGxlIG51bWJlcnMuCgpgYGB7cn0KcGF0aHdheXMgPC0gYygiTEVGMV9VUC5WMV9VUCIsICJTTkY1X0ROLlYxX1VQIiwgIk1FS19VUC5WMV9ETiIpCnkgPC0gc3NHU0VBLmRhdGEkd1ttYXRjaChwYXRod2F5cyxyb3duYW1lcyhzc0dTRUEuZGF0YSR3KSksXQp5IDwtIHJlbW92ZUJhdGNoRWZmZWN0KHksZGVzaWduID0gbW9kZWwubWF0cml4KH50cmVhdG1lbnQpLCBiYXRjaD1wZHgsIGJhdGNoMiA9IHNlcXVlbmNpbmcpCmZvcihpIGluIDE6bGVuZ3RoKHBhdGh3YXlzKSl7CiAgeCA8LSB5W2ksXQogIHN0cmlwY2hhcnQoeH50cmVhdG1lbnQqcGR4LHZlcnRpY2FsPVRSVUUsbGFzPTIsY2V4LmF4aXM9MC44LHBjaD0xNixjb2w9MToyLG1ldGhvZD0iaml0dGVyIixtYWluPXBhdGh3YXlzW2ldKQp9CmBgYAoKClNoaWZ0cyBvZiBtZWFuIHcuci50LiBQRFggbW9kZWxzCgpgYGB7cn0KeCA8LSBhcHBseSh5LDEsZnVuY3Rpb24oeCkgYXMubnVtZXJpYyhieSh4LGludGVyYWN0aW9uKHRyZWF0bWVudCxwZHgpLG1lYW4pKSkKeCA8LSB4W3NlcSgxLGJ5PTIsbGVuZ3RoLm91dCA9IGxlbmd0aCh1bmlxdWUocGR4KSkpLF0gLSB4W3NlcSgyLGJ5PTIsbGVuZ3RoLm91dCA9IGxlbmd0aCh1bmlxdWUocGR4KSkpLF0Kcm93bmFtZXMoeCkgPC0gc29ydCh1bmlxdWUocGR4KSkKeCA8LSBhcy5kYXRhLnRhYmxlKG1lbHQoeCkpCmdncGxvdCh4KSArIGFlcyh4PVZhcjEseT12YWx1ZSkgKyBnZW9tX2NvbCgpICsgZmFjZXRfd3JhcCh+VmFyMikgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkKYGBgCgpSZXBlYXQgYWJvdmUgd2l0aCBtZWRpYW4gKGxlc3MgYWZmZWN0ZWQgYnkgb3V0bGllcnMpCgpgYGB7cn0KeCA8LSBhcHBseSh5LDEsZnVuY3Rpb24oeCkgYXMubnVtZXJpYyhieSh4LGludGVyYWN0aW9uKHRyZWF0bWVudCxwZHgpLG1lZGlhbikpKQp4IDwtIHhbc2VxKDEsYnk9MixsZW5ndGgub3V0ID0gbGVuZ3RoKHVuaXF1ZShwZHgpKSksXSAtIHhbc2VxKDIsYnk9MixsZW5ndGgub3V0ID0gbGVuZ3RoKHVuaXF1ZShwZHgpKSksXQpyb3duYW1lcyh4KSA8LSBzb3J0KHVuaXF1ZShwZHgpKQp4IDwtIGFzLmRhdGEudGFibGUobWVsdCh4KSkKZ2dwbG90KHgpICsgYWVzKHg9VmFyMSx5PXZhbHVlKSArIGdlb21fY29sKCkgKyBmYWNldF93cmFwKH5WYXIyKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApKQpgYGAKCiMgTW9kZWw6IH4gZHJ1ZzpwZHgKCmBgYHtyfQpzZXF1ZW5jaW5nIDwtIHJuYXNlcSRtZXRhWyxmYWN0b3IobWVyZ2VkLmxhbmVzKV0KdHJlYXRtZW50IDwtIHJuYXNlcSRtZXRhWyxUcmVhdG1lbnRdCnBkeCA8LSBybmFzZXEkbWV0YVssUERYXQoKZCA8LSBtb2RlbC5tYXRyaXgofiAwICsgc2VxdWVuY2luZyArIHRyZWF0bWVudDpwZHgpCmQgPC0gZFssY29sU3VtcyhkKSE9MF0KZCA8LSBkWywhKGNvbG5hbWVzKGQpICVpbiUgYygic2VxdWVuY2luZzMiKSldCgpjIDwtIG1hdHJpeCgwLGRpbShkKVsyXSxsZW5ndGgodW5pcXVlKHBkeCkpKQpjW2NiaW5kKHNlcSgxLGJ5PTIsbGVuZ3RoLm91dD1sZW5ndGgodW5pcXVlKHBkeCkpKSArIChsZW5ndGgobGV2ZWxzKHNlcXVlbmNpbmcpKS0xKSwxOmxlbmd0aCh1bmlxdWUocGR4KSkpXSA8LSAxCmNbY2JpbmQoc2VxKDIsYnk9MixsZW5ndGgub3V0PWxlbmd0aCh1bmlxdWUocGR4KSkpICsgKGxlbmd0aChsZXZlbHMoc2VxdWVuY2luZykpLTEpLDE6bGVuZ3RoKHVuaXF1ZShwZHgpKSldIDwtIC0xCmNvbG5hbWVzKGMpIDwtIHBhc3RlKHNvcnQodW5pcXVlKHBkeCkpLCJTZWx1Lm1pbnVzLmNvbnRyb2wiLHNlcD0iOiIpCnJvd25hbWVzKGMpIDwtIGNvbG5hbWVzKGQpCmMKCkRFLmRhdGEgPC0gREUucnVuKHJuYXNlcSRodW1hbixkLDIsY29udC5tYXRyaXggPSBjKQoKI1RhYmxlIG9mIERFIGdlbmVzCkRFIDwtIGRlY2lkZVRlc3QuYW5ub3RhdGVkLkRFKERFLmRhdGEkZWZpdCxwLnZhbCA9IDAuMDUpCkRFCgojVmVubkRpYWdybXMgb2YgREUgZ2VuZXMKaWYobnJvdyhERSkhPTApIHZlbm5EaWFncmFtLnBhaXJlZChERVssMjo2XSkKYGBgCgojIFZISU8wOTgKIyMgT25seSBWSElPMDk4LW5haXZlIChNb2RlbDogfiBkcnVnKQoKYGBge3J9ClZISSA8LSBzdWJzZXQuUERYKHJuYXNlcSxybmFzZXEkbWV0YVssUERYPT0iVkhJTzA5OCIgJiBUcmVhdG1lbnQhPSJVbmtub3duIl0pCnRyZWF0bWVudCA8LSBWSEkkbWV0YVssVHJlYXRtZW50XQpzZXF1ZW5jaW5nIDwtIFZISSRtZXRhWyxmYWN0b3IobWVyZ2VkLmxhbmVzKV0KI2QgPC0gbW9kZWwubWF0cml4KH4gMCArIHRyZWF0bWVudCArIHNlcXVlbmNpbmcpCmQgPC0gbW9kZWwubWF0cml4KH4gMCArIHRyZWF0bWVudCkgIzwtIEJhZCBBbGkKCgpjb250Lm1hdHJpeCA8LSBtYXRyaXgoYygxLC0xLHJlcCgwLGRpbShkKVsyXS0yKSksIGRpbShkKVsyXSwgMSkKY29sbmFtZXMoY29udC5tYXRyaXgpIDwtIGMoIlNlbHUubWludXMuY29udHJvbCIpCnJvd25hbWVzKGNvbnQubWF0cml4KSA8LSBjb2xuYW1lcyhkKQpjb250Lm1hdHJpeAoKI1BlcmZvcm0gREUKREUuZGF0YSA8LSBERS5ydW4oVkhJJGh1bWFuLGQsMixjb250Lm1hdHJpeCA9IGNvbnQubWF0cml4KQoKI1RvcCBERSBnZW5lcyB0YWJsZQpERSA8LSB0b3BUYWJsZS5hbm5vdGF0ZWQuREUoREUuZGF0YSRlZml0LHAudmFsID0gMC41KQppZihucm93KERFKSE9MCl7CiAgdGFibGUoREVbLGRpcmVjdGlvbl0pCiAgREVbZGlyZWN0aW9uPT0idXAucmVnIiwuKGRpcmVjdGlvbixFTlNFTUJMLFNZTUJPTCxhZGouUC5WYWwsbG9nRkMpXQogIERFW2RpcmVjdGlvbj09ImRvd24ucmVnIiwuKGRpcmVjdGlvbixFTlNFTUJMLFNZTUJPTCxhZGouUC5WYWwsbG9nRkMpXQoKI1BoZWF0bWFwIHcvIGJhdGNoIGNvcnJlY3Rpb24KICBpIDwtIG1hdGNoKERFJEVOU0VNQkwscm93bmFtZXMoREUuZGF0YSR2JEUpKQogIHkgPC0gcmVtb3ZlQmF0Y2hFZmZlY3QoREUuZGF0YSR2JEVbaSxdLGRlc2lnbiA9IG1vZGVsLm1hdHJpeCh+ZHJ1ZyksIGJhdGNoPSBwZHgpCiAgbGFiZWxzLmNvbCA8LSByZXAoIiIsbnJvdyhybmFzZXEkbWV0YSkpCiAgbGFiZWxzLnJvdyA8LSBERSRTWU1CT0wKICBhbm4uY29sIDwtIGFzLmRhdGEuZnJhbWUocm5hc2VxJG1ldGFbLC4ocGR4LGRydWcpXSkKICByb3duYW1lcyhhbm4uY29sKSA8LSBybmFzZXEkbWV0YVssU2FtcGxlLm5hbWVdCiAgcGhlYXRtYXAoeSxsYWJlbHNfY29sPWxhYmVscy5jb2wsbGFiZWxzX3Jvdz1sYWJlbHMucm93LGFubm90YXRpb25fY29sID0gYW5uLmNvbCxzY2FsZT0icm93IikKfQoKI0dTRUEgLSBjMgpnc2VhIDwtIEdTRUEucnVuKERFLmRhdGEkdixkLGNvbnQubWF0cml4WywxXSxIcy5jMiwwLjA1KQpnc2VhW0RpcmVjdGlvbj09IlVwIiwuKHJuLE5HZW5lcyxEaXJlY3Rpb24sRkRSKV0KZ3NlYVtEaXJlY3Rpb249PSJEb3duIiwuKHJuLE5HZW5lcyxEaXJlY3Rpb24sRkRSKV0KCiNHU0VBIC0gYzYKZ3NlYSA8LSBHU0VBLnJ1bihERS5kYXRhJHYsZCxjb250Lm1hdHJpeFssMV0sSHMuYzYsMC4wNSkKZ3NlYVtEaXJlY3Rpb249PSJVcCIsLihybixOR2VuZXMsRGlyZWN0aW9uLEZEUildCmdzZWFbRGlyZWN0aW9uPT0iRG93biIsLihybixOR2VuZXMsRGlyZWN0aW9uLEZEUildCgojc3NHU0VBIC0gYzYKc3NHU0VBLmRhdGEgPC0gc3NHU0VBLnJ1bihERS5kYXRhJHYkRSxIcy5jNixkLGNvbnQubWF0cml4PWNvbnQubWF0cml4KQoKI1RvcCBERSBnZW5lLnNldHMgdGFibGUKc3NHU0VBIDwtIHRvcFRhYmxlLmFubm90YXRlZC5zc0dTRUEoc3NHU0VBLmRhdGEkZWZpdCkKaWYobnJvdyhzc0dTRUEpIT0wKXsKICBzc0dTRUFbZGlyZWN0aW9uPT0idXAucmVnIiwuKGRpcmVjdGlvbixnZW5lLnNldCxhZGouUC5WYWwsbG9nRkMpXQogIHNzR1NFQVtkaXJlY3Rpb249PSJkb3duLnJlZyIsLihkaXJlY3Rpb24sZ2VuZS5zZXQsYWRqLlAuVmFsLGxvZ0ZDKV0KfQoKaWYobnJvdyhzc0dTRUEpPjEpewogICNQaGVhdG1hcCB3LyBiYXRjaCBjb3JyZWN0aW9uCiAgaSA8LSBtYXRjaChzc0dTRUEkZ2VuZS5zZXQscm93bmFtZXMoc3NHU0VBLmRhdGEkdykpCiAgbGFiZWxzLmNvbCA8LSByZXAoIiIsbnJvdyhWSEkkbWV0YSkpCiAgbGFiZWxzLnJvdyA8LSBzc0dTRUEkZ2VuZS5zZXQKICBhbm4uY29sIDwtIGFzLmRhdGEuZnJhbWUoVkhJJG1ldGFbLC4odHJlYXRtZW50KV0pCiAgcm93bmFtZXMoYW5uLmNvbCkgPC0gVkhJJG1ldGFbLFNhbXBsZS5uYW1lXQogIHBoZWF0bWFwKHNzR1NFQS5kYXRhJHdbaSxdLGxhYmVsc19jb2w9bGFiZWxzLmNvbCxsYWJlbHNfcm93PWxhYmVscy5yb3csYW5ub3RhdGlvbl9jb2wgPSBhbm4uY29sLHNjYWxlPSJyb3ciKQp9CmBgYAoKIyMgT25seSBWSElPMDk4T1IgKE1vZGVsOiB+IGRydWcpCgpgYGB7cn0KVkhJTy5PUiA8LSBzdWJzZXQuUERYKHJuYXNlcSxybmFzZXEkbWV0YVssUERYPT0iVkhJTzA5OE9SIl0pCnRyZWF0bWVudCA8LSBWSElPLk9SJG1ldGFbLFRyZWF0bWVudF0KZCA8LSBtb2RlbC5tYXRyaXgofiAwICsgdHJlYXRtZW50KQoKY29udC5tYXRyaXggPC0gbWF0cml4KGMoMSwtMSxyZXAoMCxkaW0oZClbMl0tMikpLCBkaW0oZClbMl0sIDEpCmNvbG5hbWVzKGNvbnQubWF0cml4KSA8LSBjKCJTZWx1Lm1pbnVzLmNvbnRyb2wiKQpyb3duYW1lcyhjb250Lm1hdHJpeCkgPC0gY29sbmFtZXMoZCkKY29udC5tYXRyaXgKCiNQZXJmb3JtIERFCkRFLmRhdGEgPC0gREUucnVuKFZISU8uT1IkaHVtYW4sZCwyLGNvbnQubWF0cml4ID0gY29udC5tYXRyaXgpCgojVG9wIERFIGdlbmVzIHRhYmxlCkRFIDwtIHRvcFRhYmxlLmFubm90YXRlZC5ERShERS5kYXRhJGVmaXQscC52YWwgPSAwLjA1KQppZihucm93KERFKSE9MCl7CiAgdGFibGUoREVbLGRpcmVjdGlvbl0pCiAgREVbZGlyZWN0aW9uPT0idXAucmVnIiwuKGRpcmVjdGlvbixFTlNFTUJMLFNZTUJPTCxhZGouUC5WYWwsbG9nRkMpXQogIERFW2RpcmVjdGlvbj09ImRvd24ucmVnIiwuKGRpcmVjdGlvbixFTlNFTUJMLFNZTUJPTCxhZGouUC5WYWwsbG9nRkMpXQoKI1BoZWF0bWFwIHcvIGJhdGNoIGNvcnJlY3Rpb24KICBpIDwtIG1hdGNoKERFJEVOU0VNQkwscm93bmFtZXMoREUuZGF0YSR2JEUpKQogIHkgPC0gcmVtb3ZlQmF0Y2hFZmZlY3QoREUuZGF0YSR2JEVbaSxdLGRlc2lnbiA9IG1vZGVsLm1hdHJpeCh+ZHJ1ZyksIGJhdGNoPSBwZHgpCiAgbGFiZWxzLmNvbCA8LSByZXAoIiIsbnJvdyhWSElPLk9SJG1ldGEpKQogIGxhYmVscy5yb3cgPC0gREUkU1lNQk9MCiAgYW5uLmNvbCA8LSBhcy5kYXRhLmZyYW1lKFZISU8uT1IkbWV0YVssLihwZHgsZHJ1ZyldKQogIHJvd25hbWVzKGFubi5jb2wpIDwtIFZISU8uT1IkbWV0YVssU2FtcGxlLm5hbWVdCiAgcGhlYXRtYXAoeSxsYWJlbHNfY29sPWxhYmVscy5jb2wsbGFiZWxzX3Jvdz1sYWJlbHMucm93LGFubm90YXRpb25fY29sID0gYW5uLmNvbCxzY2FsZT0icm93IikKfQoKI0dTRUEgLSBjMgpnc2VhIDwtIEdTRUEucnVuKERFLmRhdGEkdixkLGNvbnQubWF0cml4WywxXSxIcy5jMiwwLjA1KQpnc2VhW0RpcmVjdGlvbj09IlVwIiwuKHJuLE5HZW5lcyxEaXJlY3Rpb24sRkRSKV0KZ3NlYVtEaXJlY3Rpb249PSJEb3duIiwuKHJuLE5HZW5lcyxEaXJlY3Rpb24sRkRSKV0KCiNHU0VBIC0gYzYKZ3NlYSA8LSBHU0VBLnJ1bihERS5kYXRhJHYsZCxjb250Lm1hdHJpeFssMV0sSHMuYzYsMC4wNSkKZ3NlYVtEaXJlY3Rpb249PSJVcCIsLihybixOR2VuZXMsRGlyZWN0aW9uLEZEUildCmdzZWFbRGlyZWN0aW9uPT0iRG93biIsLihybixOR2VuZXMsRGlyZWN0aW9uLEZEUildCgojc3NHU0VBIC0gYzYKc3NHU0VBLmRhdGEgPC0gc3NHU0VBLnJ1bihERS5kYXRhJHYkRSxIcy5jNixkLGNvbnQubWF0cml4PWNvbnQubWF0cml4KQoKI1RvcCBERSBnZW5lLnNldHMgdGFibGUKc3NHU0VBIDwtIHRvcFRhYmxlLmFubm90YXRlZC5zc0dTRUEoc3NHU0VBLmRhdGEkZWZpdCkKaWYobnJvdyhzc0dTRUEpIT0wKXsKICBzc0dTRUFbZGlyZWN0aW9uPT0idXAucmVnIiwuKGRpcmVjdGlvbixnZW5lLnNldCxhZGouUC5WYWwsbG9nRkMpXQogIHNzR1NFQVtkaXJlY3Rpb249PSJkb3duLnJlZyIsLihkaXJlY3Rpb24sZ2VuZS5zZXQsYWRqLlAuVmFsLGxvZ0ZDKV0KfQoKaWYobnJvdyhzc0dTRUEpPjEpewogICNQaGVhdG1hcCB3LyBiYXRjaCBjb3JyZWN0aW9uCiAgaSA8LSBtYXRjaChzc0dTRUEkZ2VuZS5zZXQscm93bmFtZXMoc3NHU0VBLmRhdGEkdykpCiAgbGFiZWxzLmNvbCA8LSByZXAoIiIsbnJvdyhWSElPLk9SJG1ldGEpKQogIGxhYmVscy5yb3cgPC0gc3NHU0VBJGdlbmUuc2V0CiAgYW5uLmNvbCA8LSBhcy5kYXRhLmZyYW1lKEhDSSRtZXRhWywuKHRyZWF0bWVudCldKQogIHJvd25hbWVzKGFubi5jb2wpIDwtIEhDSSRtZXRhWyxTYW1wbGUubmFtZV0KICBwaGVhdG1hcChzc0dTRUEuZGF0YSR3W2ksXSxsYWJlbHNfY29sPWxhYmVscy5jb2wsbGFiZWxzX3Jvdz1sYWJlbHMucm93LGFubm90YXRpb25fY29sID0gYW5uLmNvbCxzY2FsZT0icm93IikKfQpgYGAKCiMjIE9ubHkgVkhJTzA5OCAody8gU2VsdSkgKE1vZGVsOiB+IFBEWCkKCmBgYHtyfQpWSElPLk9SIDwtIHN1YnNldC5QRFgocm5hc2VxLHJuYXNlcSRtZXRhWyxQRFggJWluJSBjKCJWSElPMDk4IiwiVkhJTzA5OE9SIikgJiBUcmVhdG1lbnQ9PSJTZWx1bWV0aW5pYiIgJiBtZXJnZWQubGFuZXM9PTFdKQptb2RlbCA8LSBWSElPLk9SJG1ldGFbLFBEWF0KZCA8LSBtb2RlbC5tYXRyaXgofiAwICsgbW9kZWwpCgpjb250Lm1hdHJpeCA8LSBtYXRyaXgoYygxLC0xLHJlcCgwLGRpbShkKVsyXS0yKSksIGRpbShkKVsyXSwgMSkKY29sbmFtZXMoY29udC5tYXRyaXgpIDwtIGMoIk9SLm1pbnVzLk5haXZlIikKcm93bmFtZXMoY29udC5tYXRyaXgpIDwtIGNvbG5hbWVzKGQpCmNvbnQubWF0cml4CgojUGVyZm9ybSBERQpERS5kYXRhIDwtIERFLnJ1bihWSElPLk9SJGh1bWFuLGQsMixjb250Lm1hdHJpeCA9IGNvbnQubWF0cml4KQoKI1RvcCBERSBnZW5lcyB0YWJsZQpERSA8LSB0b3BUYWJsZS5hbm5vdGF0ZWQuREUoREUuZGF0YSRlZml0LHAudmFsID0gMC4wNSkKaWYobnJvdyhERSkhPTApewogIHRhYmxlKERFWyxkaXJlY3Rpb25dKQogIERFW2RpcmVjdGlvbj09InVwLnJlZyIsLihkaXJlY3Rpb24sRU5TRU1CTCxTWU1CT0wsYWRqLlAuVmFsLGxvZ0ZDKV0KICBERVtkaXJlY3Rpb249PSJkb3duLnJlZyIsLihkaXJlY3Rpb24sRU5TRU1CTCxTWU1CT0wsYWRqLlAuVmFsLGxvZ0ZDKV0KCiNQaGVhdG1hcCB3LyBiYXRjaCBjb3JyZWN0aW9uCiAgaSA8LSBtYXRjaChERSRFTlNFTUJMLHJvd25hbWVzKERFLmRhdGEkdiRFKSkKICB5IDwtIERFLmRhdGEkdiRFW2ksXQogIGxhYmVscy5jb2wgPC0gcmVwKCIiLG5yb3coVkhJTy5PUiRtZXRhKSkKICBsYWJlbHMucm93IDwtIERFJFNZTUJPTAogIGFubi5jb2wgPC0gYXMuZGF0YS5mcmFtZShWSElPLk9SJG1ldGFbLC4oUERYKV0pCiAgcm93bmFtZXMoYW5uLmNvbCkgPC0gVkhJTy5PUiRtZXRhWyxTYW1wbGUubmFtZV0KICBwaGVhdG1hcCh5LGxhYmVsc19jb2w9bGFiZWxzLmNvbCxsYWJlbHNfcm93PWxhYmVscy5yb3csYW5ub3RhdGlvbl9jb2wgPSBhbm4uY29sLHNjYWxlPSJyb3ciKQp9CgojR1NFQSAtIGMyCmdzZWEgPC0gR1NFQS5ydW4oREUuZGF0YSR2LGQsY29udC5tYXRyaXhbLDFdLEhzLmMyLDAuMDUpCmdzZWFbRGlyZWN0aW9uPT0iVXAiLC4ocm4sTkdlbmVzLERpcmVjdGlvbixGRFIpXQpnc2VhW0RpcmVjdGlvbj09IkRvd24iLC4ocm4sTkdlbmVzLERpcmVjdGlvbixGRFIpXQoKI0dTRUEgLSBjNgpnc2VhIDwtIEdTRUEucnVuKERFLmRhdGEkdixkLGNvbnQubWF0cml4WywxXSxIcy5jNiwwLjA1KQpnc2VhW0RpcmVjdGlvbj09IlVwIiwuKHJuLE5HZW5lcyxEaXJlY3Rpb24sRkRSKV0KZ3NlYVtEaXJlY3Rpb249PSJEb3duIiwuKHJuLE5HZW5lcyxEaXJlY3Rpb24sRkRSKV0KCiNzc0dTRUEgLSBjNgpzc0dTRUEuZGF0YSA8LSBzc0dTRUEucnVuKERFLmRhdGEkdiRFLEhzLmM2LGQsY29udC5tYXRyaXg9Y29udC5tYXRyaXgpCgojVG9wIERFIGdlbmUuc2V0cyB0YWJsZQpzc0dTRUEgPC0gdG9wVGFibGUuYW5ub3RhdGVkLnNzR1NFQShzc0dTRUEuZGF0YSRlZml0KQppZihucm93KHNzR1NFQSkhPTApewogIHNzR1NFQVtkaXJlY3Rpb249PSJ1cC5yZWciLC4oZGlyZWN0aW9uLGdlbmUuc2V0LGFkai5QLlZhbCxsb2dGQyldCiAgc3NHU0VBW2RpcmVjdGlvbj09ImRvd24ucmVnIiwuKGRpcmVjdGlvbixnZW5lLnNldCxhZGouUC5WYWwsbG9nRkMpXQp9CgppZihucm93KHNzR1NFQSk+MSl7CiAgI1BoZWF0bWFwIHcvIGJhdGNoIGNvcnJlY3Rpb24KICBpIDwtIG1hdGNoKHNzR1NFQSRnZW5lLnNldCxyb3duYW1lcyhzc0dTRUEuZGF0YSR3KSkKICBsYWJlbHMuY29sIDwtIHJlcCgiIixucm93KFZISU8uT1IkbWV0YSkpCiAgbGFiZWxzLnJvdyA8LSBzc0dTRUEkZ2VuZS5zZXQKICBhbm4uY29sIDwtIGFzLmRhdGEuZnJhbWUoSENJJG1ldGFbLC4odHJlYXRtZW50KV0pCiAgcm93bmFtZXMoYW5uLmNvbCkgPC0gSENJJG1ldGFbLFNhbXBsZS5uYW1lXQogIHBoZWF0bWFwKHNzR1NFQS5kYXRhJHdbaSxdLGxhYmVsc19jb2w9bGFiZWxzLmNvbCxsYWJlbHNfcm93PWxhYmVscy5yb3csYW5ub3RhdGlvbl9jb2wgPSBhbm4uY29sLHNjYWxlPSJyb3ciKQp9CmBgYAoKIyBPdGhlciBtb2RlbHMKCiMjIE9ubHkgU1RHMTM5IChNb2RlbDogfiBkcnVnKQoKYGBge3J9ClNURzEzOSA8LSBzdWJzZXQuUERYKHJuYXNlcSxybmFzZXEkbWV0YVssUERYPT0iU1RHMTM5IiAmIG1lcmdlZC5sYW5lcz09MV0pCnRyZWF0bWVudCA8LSBTVEcxMzkkbWV0YVssVHJlYXRtZW50XQpkIDwtIG1vZGVsLm1hdHJpeCh+IDAgKyB0cmVhdG1lbnQpCgpjb250Lm1hdHJpeCA8LSBtYXRyaXgoYygxLC0xLHJlcCgwLGRpbShkKVsyXS0yKSksIGRpbShkKVsyXSwgMSkKY29sbmFtZXMoY29udC5tYXRyaXgpIDwtIGMoIlNlbHUubWludXMuY29udHJvbCIpCnJvd25hbWVzKGNvbnQubWF0cml4KSA8LSBjb2xuYW1lcyhkKQpjb250Lm1hdHJpeAoKI1BlcmZvcm0gREUKREUuZGF0YSA8LSBERS5ydW4oU1RHMTM5JGh1bWFuLGQsMixjb250Lm1hdHJpeCA9IGNvbnQubWF0cml4KQoKI1RvcCBERSBnZW5lcyB0YWJsZQpERSA8LSB0b3BUYWJsZS5hbm5vdGF0ZWQuREUoREUuZGF0YSRlZml0LHAudmFsID0gMC4wNSkKaWYobnJvdyhERSkhPTApewogIHRhYmxlKERFWyxkaXJlY3Rpb25dKQogIERFW2RpcmVjdGlvbj09InVwLnJlZyIsLihkaXJlY3Rpb24sRU5TRU1CTCxTWU1CT0wsYWRqLlAuVmFsLGxvZ0ZDKV0KICBERVtkaXJlY3Rpb249PSJkb3duLnJlZyIsLihkaXJlY3Rpb24sRU5TRU1CTCxTWU1CT0wsYWRqLlAuVmFsLGxvZ0ZDKV0KCiNQaGVhdG1hcCB3LyBiYXRjaCBjb3JyZWN0aW9uCiAgaSA8LSBtYXRjaChERSRFTlNFTUJMLHJvd25hbWVzKERFLmRhdGEkdiRFKSkKICB5IDwtIHJlbW92ZUJhdGNoRWZmZWN0KERFLmRhdGEkdiRFW2ksXSxkZXNpZ24gPSBtb2RlbC5tYXRyaXgofmRydWcpLCBiYXRjaD0gcGR4KQogIGxhYmVscy5jb2wgPC0gcmVwKCIiLG5yb3coU1RHMTM5JG1ldGEpKQogIGxhYmVscy5yb3cgPC0gREUkU1lNQk9MCiAgYW5uLmNvbCA8LSBhcy5kYXRhLmZyYW1lKFNURzEzOSRtZXRhWywuKHBkeCxkcnVnKV0pCiAgcm93bmFtZXMoYW5uLmNvbCkgPC0gU1RHMTM5JG1ldGFbLFNhbXBsZS5uYW1lXQogIHBoZWF0bWFwKHksbGFiZWxzX2NvbD1sYWJlbHMuY29sLGxhYmVsc19yb3c9bGFiZWxzLnJvdyxhbm5vdGF0aW9uX2NvbCA9IGFubi5jb2wsc2NhbGU9InJvdyIpCn0KCiNHU0VBIC0gYzIKZ3NlYSA8LSBHU0VBLnJ1bihERS5kYXRhJHYsZCxjb250Lm1hdHJpeFssMV0sSHMuYzIsMC4wNSkKZ3NlYVtEaXJlY3Rpb249PSJVcCIsLihybixOR2VuZXMsRGlyZWN0aW9uLEZEUildCmdzZWFbRGlyZWN0aW9uPT0iRG93biIsLihybixOR2VuZXMsRGlyZWN0aW9uLEZEUildCgojR1NFQSAtIGM2CmdzZWEgPC0gR1NFQS5ydW4oREUuZGF0YSR2LGQsY29udC5tYXRyaXhbLDFdLEhzLmM2LDAuMDUpCmdzZWFbRGlyZWN0aW9uPT0iVXAiLC4ocm4sTkdlbmVzLERpcmVjdGlvbixGRFIpXQpnc2VhW0RpcmVjdGlvbj09IkRvd24iLC4ocm4sTkdlbmVzLERpcmVjdGlvbixGRFIpXQoKI3NzR1NFQSAtIGM2CnNzR1NFQS5kYXRhIDwtIHNzR1NFQS5ydW4oREUuZGF0YSR2JEUsSHMuYzYsZCxjb250Lm1hdHJpeD1jb250Lm1hdHJpeCkKCiNUb3AgREUgZ2VuZS5zZXRzIHRhYmxlCnNzR1NFQSA8LSB0b3BUYWJsZS5hbm5vdGF0ZWQuc3NHU0VBKHNzR1NFQS5kYXRhJGVmaXQpCmlmKG5yb3coc3NHU0VBKSE9MCl7CiAgc3NHU0VBW2RpcmVjdGlvbj09InVwLnJlZyIsLihkaXJlY3Rpb24sZ2VuZS5zZXQsYWRqLlAuVmFsLGxvZ0ZDKV0KICBzc0dTRUFbZGlyZWN0aW9uPT0iZG93bi5yZWciLC4oZGlyZWN0aW9uLGdlbmUuc2V0LGFkai5QLlZhbCxsb2dGQyldCn0KCmlmKG5yb3coc3NHU0VBKT4xKXsKICAjUGhlYXRtYXAgdy8gYmF0Y2ggY29ycmVjdGlvbgogIGkgPC0gbWF0Y2goc3NHU0VBJGdlbmUuc2V0LHJvd25hbWVzKHNzR1NFQS5kYXRhJHcpKQogIGxhYmVscy5jb2wgPC0gcmVwKCIiLG5yb3coU1RHMTM5JG1ldGEpKQogIGxhYmVscy5yb3cgPC0gc3NHU0VBJGdlbmUuc2V0CiAgYW5uLmNvbCA8LSBhcy5kYXRhLmZyYW1lKEhDSSRtZXRhWywuKHRyZWF0bWVudCldKQogIHJvd25hbWVzKGFubi5jb2wpIDwtIEhDSSRtZXRhWyxTYW1wbGUubmFtZV0KICBwaGVhdG1hcChzc0dTRUEuZGF0YSR3W2ksXSxsYWJlbHNfY29sPWxhYmVscy5jb2wsbGFiZWxzX3Jvdz1sYWJlbHMucm93LGFubm90YXRpb25fY29sID0gYW5uLmNvbCxzY2FsZT0icm93IikKfQpgYGAKCiMjIE9ubHkgSENJMDA5IChNb2RlbDogfiBkcnVnKQoKYGBge3J9CkhDSSA8LSBzdWJzZXQuUERYKHJuYXNlcSxybmFzZXEkbWV0YVssUERYPT0iSENJMDA5Il0pCnRyZWF0bWVudCA8LSBIQ0kkbWV0YVssVHJlYXRtZW50XQpzZXF1ZW5jaW5nIDwtIEhDSSRtZXRhWyxmYWN0b3IobWVyZ2VkLmxhbmVzKV0KZCA8LSBtb2RlbC5tYXRyaXgofiAwICsgdHJlYXRtZW50ICsgc2VxdWVuY2luZykKCmNvbnQubWF0cml4IDwtIG1hdHJpeChjKDEsLTEscmVwKDAsZGltKGQpWzJdLTIpKSwgZGltKGQpWzJdLCAxKQpjb2xuYW1lcyhjb250Lm1hdHJpeCkgPC0gYygiU2VsdS5taW51cy5jb250cm9sIikKcm93bmFtZXMoY29udC5tYXRyaXgpIDwtIGNvbG5hbWVzKGQpCmNvbnQubWF0cml4CgojUGVyZm9ybSBERQpERS5kYXRhIDwtIERFLnJ1bihIQ0kkaHVtYW4sZCwyLGNvbnQubWF0cml4ID0gY29udC5tYXRyaXgpCgojVG9wIERFIGdlbmVzIHRhYmxlCkRFIDwtIHRvcFRhYmxlLmFubm90YXRlZC5ERShERS5kYXRhJGVmaXQscC52YWwgPSAwLjA1KQppZihucm93KERFKSE9MCl7CiAgdGFibGUoREVbLGRpcmVjdGlvbl0pCiAgREVbZGlyZWN0aW9uPT0idXAucmVnIiwuKGRpcmVjdGlvbixFTlNFTUJMLFNZTUJPTCxhZGouUC5WYWwsbG9nRkMpXQogIERFW2RpcmVjdGlvbj09ImRvd24ucmVnIiwuKGRpcmVjdGlvbixFTlNFTUJMLFNZTUJPTCxhZGouUC5WYWwsbG9nRkMpXQoKI1BoZWF0bWFwIHcvIGJhdGNoIGNvcnJlY3Rpb24KICBpIDwtIG1hdGNoKERFJEVOU0VNQkwscm93bmFtZXMoREUuZGF0YSR2JEUpKQogIHkgPC0gcmVtb3ZlQmF0Y2hFZmZlY3QoREUuZGF0YSR2JEVbaSxdLGRlc2lnbiA9IG1vZGVsLm1hdHJpeCh+ZHJ1ZyksIGJhdGNoPSBwZHgpCiAgbGFiZWxzLmNvbCA8LSByZXAoIiIsbnJvdyhybmFzZXEkbWV0YSkpCiAgbGFiZWxzLnJvdyA8LSBERSRTWU1CT0wKICBhbm4uY29sIDwtIGFzLmRhdGEuZnJhbWUocm5hc2VxJG1ldGFbLC4ocGR4LGRydWcpXSkKICByb3duYW1lcyhhbm4uY29sKSA8LSBybmFzZXEkbWV0YVssU2FtcGxlLm5hbWVdCiAgcGhlYXRtYXAoeSxsYWJlbHNfY29sPWxhYmVscy5jb2wsbGFiZWxzX3Jvdz1sYWJlbHMucm93LGFubm90YXRpb25fY29sID0gYW5uLmNvbCxzY2FsZT0icm93IikKfQoKI0dTRUEgLSBjMgpnc2VhIDwtIEdTRUEucnVuKERFLmRhdGEkdixkLGNvbnQubWF0cml4WywxXSxIcy5jMiwwLjA1KQpnc2VhW0RpcmVjdGlvbj09IlVwIiwuKHJuLE5HZW5lcyxEaXJlY3Rpb24sRkRSKV0KZ3NlYVtEaXJlY3Rpb249PSJEb3duIiwuKHJuLE5HZW5lcyxEaXJlY3Rpb24sRkRSKV0KCiNHU0VBIC0gYzYKZ3NlYSA8LSBHU0VBLnJ1bihERS5kYXRhJHYsZCxjb250Lm1hdHJpeFssMV0sSHMuYzYsMC4wNSkKZ3NlYVtEaXJlY3Rpb249PSJVcCIsLihybixOR2VuZXMsRGlyZWN0aW9uLEZEUildCmdzZWFbRGlyZWN0aW9uPT0iRG93biIsLihybixOR2VuZXMsRGlyZWN0aW9uLEZEUildCgojc3NHU0VBIC0gYzYKc3NHU0VBLmRhdGEgPC0gc3NHU0VBLnJ1bihERS5kYXRhJHYkRSxIcy5jNixkLGNvbnQubWF0cml4PWNvbnQubWF0cml4KQoKI1RvcCBERSBnZW5lLnNldHMgdGFibGUKc3NHU0VBIDwtIHRvcFRhYmxlLmFubm90YXRlZC5zc0dTRUEoc3NHU0VBLmRhdGEkZWZpdCkKaWYobnJvdyhzc0dTRUEpIT0wKXsKICBzc0dTRUFbZGlyZWN0aW9uPT0idXAucmVnIiwuKGRpcmVjdGlvbixnZW5lLnNldCxhZGouUC5WYWwsbG9nRkMpXQogIHNzR1NFQVtkaXJlY3Rpb249PSJkb3duLnJlZyIsLihkaXJlY3Rpb24sZ2VuZS5zZXQsYWRqLlAuVmFsLGxvZ0ZDKV0KfQoKaWYobnJvdyhzc0dTRUEpPjEpewogICNQaGVhdG1hcCB3LyBiYXRjaCBjb3JyZWN0aW9uCiAgaSA8LSBtYXRjaChzc0dTRUEkZ2VuZS5zZXQscm93bmFtZXMoc3NHU0VBLmRhdGEkdykpCiAgbGFiZWxzLmNvbCA8LSByZXAoIiIsbnJvdyhIQ0kkbWV0YSkpCiAgbGFiZWxzLnJvdyA8LSBzc0dTRUEkZ2VuZS5zZXQKICBhbm4uY29sIDwtIGFzLmRhdGEuZnJhbWUoSENJJG1ldGFbLC4odHJlYXRtZW50KV0pCiAgcm93bmFtZXMoYW5uLmNvbCkgPC0gSENJJG1ldGFbLFNhbXBsZS5uYW1lXQogIHBoZWF0bWFwKHNzR1NFQS5kYXRhJHdbaSxdLGxhYmVsc19jb2w9bGFiZWxzLmNvbCxsYWJlbHNfcm93PWxhYmVscy5yb3csYW5ub3RhdGlvbl9jb2wgPSBhbm4uY29sLHNjYWxlPSJyb3ciKQp9CmBgYAoKCg==